How the repo is structured: modules, auto-configuration order, runtime wiring, and how to run the demo.
Also see: LIBRARY.md (Maven name, why adopt, discoverability), USAGE.md (feature usage, sequence, data, exceptions), GOVERNANCE.md (decisions, reason codes), FAILURE_MODES.md (audit modes, failures), QUICKSTART.md (minimal app).
flowchart BT
demo[agc-demo-app]
api[agc-api]
starter[agc-spring-boot-starter]
autoconf[agc-spring-boot-autoconfigure]
orch[agc-orchestrator]
mcp[agc-mcp]
pol[agc-policy]
gr[agc-guardrail]
aud[agc-audit]
stor[agc-storage]
obs[agc-observability]
core[agc-core]
demo --> api
demo --> starter
starter --> autoconf
autoconf --> orch
autoconf --> mcp
autoconf --> pol
autoconf --> gr
autoconf --> aud
autoconf --> stor
autoconf --> obs
autoconf --> api
api --> orch
api --> stor
orch --> mcp
mcp --> pol
mcp --> gr
mcp --> aud
aud --> stor
stor --> core
pol --> core
gr --> core
mcp --> core
orch --> core
aud --> core
- Starter →
agc-spring-boot-autoconfigureonly; that module pulls feature JARs and registers all@AutoConfigurationclasses. McpToolExecutoriscom.framework.agent.mcp.internal(not publicagc-coreAPI). ArchUnit enforces gateway-only execution paths.
| Area | Package | Module |
|---|---|---|
| Domain + gateway SPI | com.framework.agent.core |
agc-core (no Spring) |
| JPA / Flyway | com.framework.agent.storage |
agc-storage |
| Audit | com.framework.agent.audit |
agc-audit |
| Policy / guardrails | com.framework.agent.policy, ..guardrail |
agc-policy, agc-guardrail |
| Pipeline + gateway | com.framework.agent.mcp |
agc-mcp |
| MCP adapter SPI | com.framework.agent.mcp.internal |
agc-mcp |
| Spring wiring | com.framework.agent.autoconfigure |
agc-spring-boot-autoconfigure |
| REST (optional) | com.framework.agent.api.web |
agc-api |
All live in agc-spring-boot-autoconfigure, file:
META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports
Chain: Storage (after DataSourceAutoConfiguration) → Audit → Policy → Guardrail → MCP (ToolRegistry + gateway + executor) → Orchestrator → Observability (if MeterRegistry) → Web (if REST classes on classpath).
- Trusted entry point:
ToolInvocationGatewayonly; internalMcpToolExecutoris blocked outside the gateway (GatewayContextHolder, ArchUnit). Direct call →IllegalStateException: "Direct execution forbidden". - Governance pipeline: registry (optional allowlist) → policy → guardrails → execution;
DecisionType.DENY→ no tool execution. Decisions and reason codes: GOVERNANCE.md. - Tool registry (first):
agc.tools.allowed; logical names andtool:vN: see Tool versioning below. Unknown tool →TOOL_NOT_REGISTEREDbefore policy. - Kill switch:
agc.enabled: false→AGC_DISABLED. Audit behavior by mode: FAILURE_MODES.md. agc.governance.mode:DEVELOPMENT|STAGING|PRODUCTION.PRODUCTION→POST /agent/executereturns 401 without authenticated Spring Security principal.agc.audit.mode:STRICT|ASYNC|BEST_EFFORT— see FAILURE_MODES.md.agc.audit.strict-secondary-audit(defaulttrue) applies toSYSTEM_ERRORafter tool failure in STRICT.
Logical phases (not a separate state machine in code): authorize (registry + policy + guardrails) → execute (internal MCP adapter) → audit (request/response/error per agc.audit.mode). Invalid paths end in DENY + audit when persistence allows.
Use logicalName:vN (e.g. search:v1). Policy, registry, and guardrails compare ToolNames.logicalName so allowlists and role bindings can stay on search while callers pass search:v2.
MDC carries traceId, correlationId, principalId, toolName, decision, reasonCode, executionTimeMs. Micrometer timers/counters are registered when a MeterRegistry bean exists; in full Spring Boot stacks, pair Micrometer + OTLP / Spring Boot 3 observability to export traces to OpenTelemetry without changing gateway code.
AgentOrchestrator → ToolInvocationGateway → ToolRegistry (allowlist / TOOL_NOT_REGISTERED) → policy → guardrails → (if not DENY) internal executor → AuditRecorder.
| Goal | Command |
|---|---|
| Build + tests | mvn clean verify |
| Demo (from repo root) | mvn -pl agc-demo-app -am spring-boot:run |
Use -am so sibling modules build in the reactor; otherwise install snapshots with mvn install from root first.
| Key | Role |
|---|---|
agc.enabled |
Global kill switch (false = deny all tool executions) |
agc.governance.mode |
DEVELOPMENT | STAGING | PRODUCTION (HTTP 401 when PRODUCTION and unauthenticated) |
agc.tools.allowed |
Optional allowlist of tool names; empty = no extra registry filter |
agc.policy.roles |
Role → allowed tools ("*" = all) |
agc.guardrails.rules |
id, toolName, action (DENY / WARN) |
agc.llm.planned-tool-name |
Stub LLM default tool |
agc.audit.mode |
STRICT | BEST_EFFORT | ASYNC (async executor bean) |
agc.audit.max-payload-chars |
Bound stored payload text |
agc.audit.hash-payload |
Optional SHA-256 payload hash (false by default) |
agc.audit.strict-secondary-audit |
Default true: fail if SYSTEM_ERROR audit cannot be written after tool failure when mode is STRICT |
Example: agc-demo-app/src/main/resources/application.yml.
curl -s -X POST http://localhost:8080/agent/execute \
-H 'Content-Type: application/json' \
-d '{"traceId":"t-1","correlationId":"c-1","principalId":"u1","roles":["user"],"message":"hello"}'GET /audit/{traceId}— audit trail for that trace.- Demo UI:
GET /·GET /demo/scenarios(each item hasid,description,group) ·POST /demo/runwith{"scenario":"<id>"}. - Stub LLM:
[[tool:name]]or[[tool:name:vN]]in the message, or scenario thread override for the planned tool.
group |
Scenario id | What it shows |
|---|---|---|
success |
allow_search |
Allowed tool for role user; audit trail |
success |
allow_search_versioned |
Planned search:v2 — registry uses logical search |
success |
allow_read_with_warn |
Guardrail WARN on read; tool still runs |
registry |
unknown_tool_not_registered |
Tool not in agc.tools.allowed → TOOL_NOT_REGISTERED |
policy |
policy_deny_forbidden_tool |
Role lacks tool → POLICY_TOOL_FORBIDDEN |
policy |
policy_deny_no_roles |
No roles → POLICY_NO_ROLES |
guardrail |
guardrail_deny_payment |
Guardrail DENY on payment_api |
| Symptom | Check |
|---|---|
| Build can’t find modules | mvn -pl agc-demo-app -am … or mvn install from root |
403 with reasonCode |
Policy roles vs tool; guardrail rules |
| Audit / DB errors | Datasource, Flyway, DB reachability |
| Invalid auto-config at startup | Clean build; autoconfigure lives only in agc-spring-boot-autoconfigure |
- Keep policy / guardrail evaluators CPU-only and non-blocking; network calls in evaluators increase governance latency and failure blast radius.
- Default recommendation:
agc.audit.mode=STRICTfor regulated production; useASYNConly with queue/backpressure monitoring. - Typical datasource baseline for audit-heavy services (Hikari):
spring.datasource.hikari.maximum-pool-size: 20spring.datasource.hikari.minimum-idle: 5spring.datasource.hikari.connection-timeout: 30000- tune per deployment throughput and DB limits.
- Key metrics:
agc_decisions_total{decision,reasonCode}agc_gateway_latency_ms{outcome}agc_audit_write_failures_totalagc_audit_latency_ms
- Add
agc-apifor REST. For headless use,agc-spring-boot-starteronly. - In production, bind identity from your auth layer, not untrusted JSON fields.
Dependency:
<dependency>
<groupId>io.github.ranasl62</groupId>
<artifactId>agc-spring-boot-starter</artifactId>
<version>1.0.0</version>
</dependency>(Publish to Maven Central / GitHub Packages is separate from cloning and mvn install.)