CodeDocs Vault

02 — Architecture

The repo is a content distribution graph that compiles to two runtimes. Once installed, an agent's actual runtime topology depends on which surface you deployed it on:

Both surfaces consume the same source-of-truth files.

High-level component map

flowchart LR
  subgraph Source["Source-of-truth (one repo)"]
    direction TB
    VP["plugins/vertical-plugins/<br/>(skills, commands, MCP configs)"]
    AP["plugins/agent-plugins/<br/>(self-contained agents)"]
    CB["managed-agent-cookbooks/<br/>(agent.yaml, subagents/, steering examples)"]
    PB["plugins/partner-built/<br/>(LSEG, S&P Global)"]
    M["marketplace.json"]
    VP -- "skills propagated by<br/>scripts/sync-agent-skills.py" --> AP
    AP -- "system: file:<br/>skills: from_plugin:" --> CB
    M --> AP
    M --> VP
    M --> PB
  end
 
  subgraph Cowork["Cowork / Claude Code (interactive)"]
    direction TB
    CL["Claude session"]
    SK["Skills auto-fired"]
    CMD["Slash commands"]
    MCP1["MCP HTTP servers"]
    CL -- triggers --> SK
    CL -- /comps, /dcf --> CMD
    CL -- tool_use --> MCP1
  end
 
  subgraph CMA["Claude Managed Agents (headless)"]
    direction TB
    DH["scripts/deploy-managed-agent.sh"]
    SUB["subagents POSTed first"]
    ORCH["orchestrator POSTed last"]
    SESS["session.steer(...)"]
    OL["scripts/orchestrate.py<br/>(reference event loop)"]
    HO["handoff_request<br/>{target_agent, payload}"]
    DH --> SUB --> ORCH
    SESS --> ORCH
    ORCH --> HO
    HO --> OL
    OL -- routes to --> SESS
  end
 
  Source -. installs .-> Cowork
  Source -. deploys via API .-> CMA

Three plugin tiers

Tier Lives in Self-contained? Purpose
Vertical plugin plugins/vertical-plugins/<vertical>/ Yes — own plugin.json, commands/, skills/, .mcp.json, hooks/ Source of truth for skills + slash commands + MCP connectors. Install on its own to get /comps, /dcf, etc.
Agent plugin plugins/agent-plugins/<slug>/ Yes — bundles a synced copy of every skill it needs The interactive form of a named workflow agent. Loadable into Cowork.
Partner plugin plugins/partner-built/<vendor>/ Yes Third-party (LSEG, S&P Global) bundles

A skill — say dcf-model — therefore lives in two places:

  1. Source: plugins/vertical-plugins/financial-analysis/skills/dcf-model/SKILL.md
  2. Bundled copy: plugins/agent-plugins/{pitch-agent,model-builder,...}/skills/dcf-model/SKILL.md

These must be byte-equal; scripts/check.py:114-131 enforces it via filecmp.dircmp. To change a skill, you edit the source and run scripts/sync-agent-skills.py, which shutil.rmtrees each bundled copy and shutil.copytrees the source in (sync-agent-skills.py:35-37).

How a managed-agent cookbook references the plugin

flowchart TB
  yaml["managed-agent-cookbooks/pitch-agent/agent.yaml"]
  sysmd["plugins/agent-plugins/pitch-agent/agents/pitch-agent.md"]
  skills["plugins/agent-plugins/pitch-agent/skills/* (bundle)"]
  vskills["plugins/vertical-plugins/*/skills/* (source)"]
  reader["./subagents/researcher.yaml"]
  modeler["./subagents/modeler.yaml"]
  deck["./subagents/deck-writer.yaml"]
 
  yaml -- "system: file: ../../plugins/agent-plugins/pitch-agent/agents/pitch-agent.md" --> sysmd
  yaml -- "skills: from_plugin: ../../plugins/agent-plugins/pitch-agent" --> skills
  yaml -- "callable_agents: manifest:" --> reader
  yaml -- " " --> modeler
  yaml -- " " --> deck
  vskills -. "synced into" .-> skills

The agent.yaml therefore has no embedded prompt and no bundled skill content — it is purely a reference document. The deploy script inlines them at POST time (deploy-managed-agent.sh:114-130):

inline_system() {
  ...
  if jq -e '.system | type == "object"' >/dev/null <<<"$json"; then
    sysfile=$(jq -r '.system.file // empty' <<<"$json")
    ...
    body="$(cat "$base/$sysfile")"
    [[ -n "$append" ]] && body="${body}"$'\n\n'"${append}"
    jq --arg s "$body" '.system=$s' <<<"$json"
  fi
}

This is why one source produces two surfaces: the cowork plugin reads the same .md interactively; the managed-agent variant inlines it into the POST body.

Managed-agent isolation tiers (the load-bearing pattern)

The most opinionated piece of the architecture. Every cookbook README has a "Security & handoffs" tier table. The shape is constant; the labels vary by agent. From managed-agent-cookbooks/gl-reconciler/README.md:24-31:

Tier Touches untrusted docs? Tools Connectors
reader Yes Read, Grep only None
Orchestrator No Read, Grep, Glob, Agent Read-only GL + subledger MCPs
resolver (Write-holder) No Read, Write, Edit None

The invariants:

  1. Exactly one worker holds Write. The "write-holder" never reads outsider documents. Writes land in ./out/.
  2. Untrusted-document readers have no MCP servers, no Bash, no Write — their only output channel is a JSON blob constrained by an output_schema: (subagents/*.yaml).
  3. The orchestrator never reads outsider documents directly — it dispatches and aggregates.
  4. A separate critic re-verifies reader output against trusted MCPs before the resolver consumes it (in gl-reconciler and earnings-reviewer).

This is structural: the system prompt asks for safe behaviour, but the tools list makes unsafe behaviour impossible.

Per-agent topologies (depth-1)

              ┌────────────────── orchestrator (read-only MCPs, Agent)
              │
   ┌──────────┴──────────────────┐
   │            │                │
 reader       critic          resolver
 (untrusted)  (re-verify)     (Write)
 schema-out   trusted MCPs    no untrusted IO

Variants seen in the cookbooks:

Cookbook Untrusted reader Trusted re-verifier Write-holder Notes
pitch-agent n/a (data is from CapIQ/Daloopa) n/a deck-writer Task-decomposition split: researcher, modeler, deck-writer
gl-reconciler reader critic resolver + Bash sandbox not needed
kyc-screener doc-reader (rules-engine) escalator UBO chart parser is read-only
earnings-reviewer transcript-reader (model-updater) note-writer Coverage list fan-out via session-per-ticker
meeting-prep-agent news-reader profiler pack-writer Briefing pack output
model-builder data-puller auditor builder The builder also has Bash (sandboxed) for openpyxl
month-end-closer ledger-reader (rollforward) poster Receives breaks from gl-reconciler
statement-auditor statement-reader reconciler flagger Pre-distribution LP-statement QC
valuation-reviewer (gp-package reader) (template runner) (LP report stager) GP packages from outside
market-researcher sector-reader comps-spreader note-writer Optional .pptx

The depth-1 invariant is asserted in CI: scripts/test-cookbooks.sh:14-17 rejects any subagent that itself defines callable_agents, and any leak of output_schema into a deployed body.

Cross-agent handoffs

Agents can request work from each other via a literal blob in the orchestrator's text output:

{"type":"handoff_request","target_agent":"<slug>","payload":{"event":"...","context_ref":"..."}}

The reference event loop in scripts/orchestrate.py watches message_delta events on the source session, regex-extracts handoff JSON (orchestrate.py:40-42), validates it (extract_handoff, orchestrate.py:45-61), and steer()s the target agent's session.

sequenceDiagram
  participant Source as Source agent (e.g. gl-reconciler)
  participant Loop as scripts/orchestrate.py
  participant Target as Target agent (e.g. month-end-closer)
 
  Source->>Loop: SSE message_delta containing<br/>{"type":"handoff_request",...}
  Loop->>Loop: HANDOFF_RE.search(text)
  Loop->>Loop: target ∈ ALLOWED_TARGETS?
  Loop->>Loop: jsonschema.validate(payload)
  Loop->>Target: client.beta.agents.sessions.steer(<br/>agent_id, input=payload.event)
  Target-->>Source: (separate session, runs to completion)

There is a deliberate security caveat in the script header (orchestrate.py:8-15): handoff text is downstream of untrusted-document readers, so a malicious document could attempt to inject a handoff blob via the orchestrator's echo channel. Mitigations:

  1. ALLOWED_TARGETS allowlist of deployed slugs (orchestrate.py:23-27).
  2. HANDOFF_PAYLOAD_SCHEMA caps event length and restricts context_ref to ^[A-Za-z0-9 ._/:#-]+$ (orchestrate.py:29-38).
  3. The script is explicitly labelled "REFERENCE ONLY" — production should "prefer emitting handoffs via a dedicated tool call or a typed SSE event the model cannot produce by quoting document text."

Data flow — single agent run (managed-agent)

Concrete example: gl-reconciler reconciling a trade date.

sequenceDiagram
  participant WE as Workflow engine (Temporal/Airflow)
  participant API as POST /v1/agents/.../sessions/.../steer
  participant Orch as gl-reconciler (orchestrator)
  participant Reader as gl-reconciler-reader (untrusted)
  participant Critic as gl-reconciler-critic
  participant Resolver as gl-reconciler-resolver (Write)
  participant GLMCP as internal-gl MCP
  participant SubMCP as subledger MCP
  participant Custodian as Custodian PDFs
 
  WE->>API: steer event: "Reconcile GL vs subledger,<br/>trade date 2026-04-30, classes: ..."
  API->>Orch: input
  Orch->>GLMCP: read GL balances (read-only)
  Orch->>SubMCP: read subledger balances (read-only)
  Orch->>Reader: dispatch per asset class
  Reader->>Custodian: Read counterparty/custodian statements
  Reader->>Reader: extract candidate breaks
  Reader-->>Orch: structured JSON (length-capped, char-class restricted)
  Orch->>Critic: re-verify each break against trusted MCPs
  Critic->>GLMCP: confirm balances
  Critic->>SubMCP: confirm balances
  Critic-->>Orch: confirmed/rejected per break
  Orch->>Resolver: verified break set
  Resolver->>Resolver: render exception report (xlsx-author skill)
  Resolver-->>Orch: ./out/exception-report.xlsx written
  Orch-->>API: final message (may include handoff_request to month-end-closer)

Key abstractions / interfaces

Abstraction Defined in Shape
Plugin plugins/*/.claude-plugin/plugin.json {name, version, description, author}
Marketplace .claude-plugin/marketplace.json {name, owner, plugins: [{name, source, description}]}
Agent system prompt plugins/agent-plugins/<slug>/agents/<slug>.md YAML frontmatter (name, description, tools) + markdown body
Skill plugins/vertical-plugins/<v>/skills/<s>/SKILL.md (and bundled) YAML frontmatter (name, description) + markdown body; may carry helper scripts
Slash command plugins/vertical-plugins/<v>/commands/<c>.md YAML frontmatter (description, argument-hint) + markdown body
MCP connector set plugins/vertical-plugins/financial-analysis/.mcp.json {mcpServers: {<name>: {type, url}}}
Managed-agent manifest (orchestrator) managed-agent-cookbooks/<slug>/agent.yaml {name, model, system, tools, mcp_servers, skills, callable_agents}
Subagent manifest managed-agent-cookbooks/<slug>/subagents/<sub>.yaml Same shape minus callable_agents, plus optional output_schema
Steering events managed-agent-cookbooks/<slug>/steering-examples.json [{event, description}, ...] — example free-text inputs
Handoff request Embedded JSON in orchestrator output {type:"handoff_request", target_agent, payload:{event, context_ref?}}

Microsoft 365 add-in tooling — separate sub-architecture

The claude-for-msft-365-install/ plugin is unrelated to the agent plugins. It is a Claude Code plugin (not Cowork) whose six commands walk an enterprise admin through:

  1. Picking a path: gateway / vertex / bedrock / foundry (commands/setup.md:36-44).
  2. Provisioning the cloud-side resource (OAuth client, IAM role, Foundry resource).
  3. Granting Azure admin consent (one-click URL).
  4. Generating the customized add-in manifest.xml via scripts/build-manifest.mjs.
  5. Optionally writing per-user routing config via Microsoft Graph extension attributes.
  6. Optionally building a "bootstrap endpoint" for per-user MCP servers + skills.

It is the on-ramp for getting the Claude Office add-in deployed in a tenant, after which the agent plugins are what runs inside it.