03 — Entry Points & Execution Flow
There are three execution entry points, one per surface.
A. Cowork / Claude Code installation (interactive)
Entry point: the user installs a plugin from the marketplace.
# Either via Cowork UI (paste repo URL in Settings → Plugins → Add plugin)
# Or via Claude Code CLI:
claude plugin marketplace add anthropics/claude-for-financial-services
claude plugin install financial-analysis@claude-for-financial-services
claude plugin install pitch-agent@claude-for-financial-services(README.md:60-69)
What the marketplace consumes: .claude-plugin/marketplace.json lists 20 plugins, each pointing at a directory under plugins/ (marketplace.json:6-107). Each of those directories has its own .claude-plugin/plugin.json with name, version, description, author.
flowchart LR
U[User] --> M[Marketplace UI / claude CLI]
M --> MJ["marketplace.json"]
MJ --> P["plugin source dir"]
P --> PJ[".claude-plugin/plugin.json"]
P --> CMD["commands/*.md"]
P --> SK["skills/*/SKILL.md"]
P --> AG["agents/*.md"]
P --> MC[".mcp.json"]
P -.-> H["hooks/*.json (currently empty)"]What happens at runtime:
- Slash commands appear:
/comps,/dcf,/earnings,/ic-memo(mapping inREADME.md:160-247). - Named agents become available in Cowork dispatch.
- Skills auto-fire when their
descriptionmatches the conversation context. - MCP connectors authenticate per-user against the providers in
plugins/vertical-plugins/financial-analysis/.mcp.json.
Hooks are scaffolded but currently empty (plugins/vertical-plugins/financial-analysis/hooks/hooks.json:1 → []; investment-banking/hooks/hooks.json → {"hooks": {}}).
B. Claude Managed Agents deployment (headless)
Entry point: scripts/deploy-managed-agent.sh <slug> (e.g. gl-reconciler).
export ANTHROPIC_API_KEY=sk-ant-...
export GL_MCP_URL=... # read-only GL MCP
export SUBLEDGER_MCP_URL=... # read-only subledger MCP
scripts/deploy-managed-agent.sh gl-reconciler(managed-agent-cookbooks/gl-reconciler/README.md:11-15)
Deploy flow (DAG)
The script walks managed-agent-cookbooks/<slug>/agent.yaml and recursively deploys subagents first, then the orchestrator. Subagents must already exist before the orchestrator can reference them by ID.
flowchart TB
start([scripts/deploy-managed-agent.sh slug])
load["yaml2json(agent.yaml)<br/>+ ${ENV} substitution<br/>(deploy-managed-agent.sh:36-52)"]
expand["resolve_manifest:<br/>expand from_plugin: → individual {path:} entries<br/>(deploy-managed-agent.sh:88-112)"]
inline["inline_system: read system.file → embed as string<br/>(deploy-managed-agent.sh:114-130)"]
loopskill{For each<br/>{path: ...}<br/>skill}
zip["cd skill/.. && zip -qr skill.zip skill"]
postskill["POST /v1/skills (multipart, beta: skills-2025-10-02)<br/>(deploy-managed-agent.sh:70-86)"]
cache["cache skill_id by basename"]
loopsub{For each<br/>callable_agents.manifest}
recurse["recurse: create_agent(subagent.yaml)"]
delout["del .output_schema before POST<br/>(deploy-managed-agent.sh:154)"]
postorch["POST /v1/agents<br/>(beta: managed-agents-2026-04-01)<br/>(deploy-managed-agent.sh:162)"]
done([echo agent id + console URL])
start --> load --> expand --> inline
inline --> loopskill
loopskill --> zip --> postskill --> cache
cache --> loopsub
loopsub --> recurse --> delout
delout --> postorch --> doneNotable transformations:
from_plugin:expansion. A singleskills: [{from_plugin: ../../plugins/agent-plugins/pitch-agent}]line in the orchestrator yaml becomes one{__upload: <abs>/skills/<each>/}per skill in that plugin (deploy-managed-agent.sh:95-105).- Skill upload caching. Skills uploaded once per run, indexed by basename in a tempfile (
deploy-managed-agent.sh:54-65). A skill referenced by orchestrator and subagent uploads only once. output_schemais deleted before POST.output_schema:is a deploy-side convenience, not an API field. The Managed Agents API doesn't enforce structured output —scripts/validate.pyis the firm-side enforcer. Kept under thedel(.output_schema)jq filter atdeploy-managed-agent.sh:154.- Env-var sandboxing.
${VAR}substitution rejects values with characters outside[A-Za-z0-9._/:@-](deploy-managed-agent.sh:43-47) — prevents shell-injection from a hostile env value into the manifest.
Dry-run mode
scripts/deploy-managed-agent.sh <slug> --dry-run produces the resolved POST bodies without contacting the API (deploy-managed-agent.sh:17-18, 173-180). scripts/test-cookbooks.sh uses this in CI to assert all 10 cookbooks resolve cleanly:
# scripts/test-cookbooks.sh:8-26 — every cookbook:
# - is valid JSON
# - has non-empty system
# - is depth-1 (subagent has no callable_agents)
# - does not leak output_schemaSteering events
After deploy, the workflow engine drives the agent with steering events. The example shapes are in steering-examples.json files. From managed-agent-cookbooks/gl-reconciler/steering-examples.json:2-13:
[
{"event": "Reconcile GL vs subledger, trade date 2026-04-30, classes: equities, fixed-income, derivatives",
"description": "Daily run across three asset classes"},
{"event": "Re-trace break: account 41200-EQ-US, trade date 2026-04-30",
"description": "Follow-up steering event to deep-dive a single break"}
]These are the user-side strings; the firm's workflow engine (Temporal / Airflow / event bus) sends them to client.beta.agents.sessions.steer(...).
Cross-agent handoff
scripts/orchestrate.py is the reference event loop. It is not the deploy entry point — it runs alongside the workflow engine to route handoff blobs.
# orchestrate.py:64-82 (paraphrased)
with client.beta.agents.sessions.stream(session_id=...) as stream:
for event in stream:
if event.type != "message_delta": continue
handoff = extract_handoff(event.text)
if not handoff: continue
target_id = agent_ids.get(handoff["target_agent"])
client.beta.agents.sessions.steer(
agent_id=target_id,
input=handoff["payload"]["event"],
)extract_handoff (orchestrate.py:45-61) regex-matches the JSON, JSON-decodes, and jsonschema.validates against HANDOFF_PAYLOAD_SCHEMA. Anything malformed is silently dropped — the agent's text continues to the user but the routing step is skipped.
C. Microsoft 365 add-in setup (admin wizard)
Entry point: the admin types /claude-for-msft-365-install:setup after installing the plugin.
claude plugin install claude-for-msft-365-install@claude-for-financial-services
# inside the session:
/claude-for-msft-365-install:setupThe slash command at claude-for-msft-365-install/commands/setup.md is itself the agent. It branches the admin through:
- Step 1 — pick
gateway/vertex/bedrock/foundry(setup.md:28-44). - Step 1b — Excel/Word/PowerPoint vs Outlook (
setup.md:51-66). Outlook is a separate manifest with extra Graph admin consent; Bedrock + Outlook is unsupported. - Per-cloud branch — provisioning steps with copy-paste console URLs and
gcloud/ IAM commands. - Generates the manifest by shelling out to
node scripts/build-manifest.mjs(setup.md:18-20). - Maintains a setup log at
~/Desktop/claude-for-msft-365-install-setup.mdso reruns can resume from where they left off (setup.md:11-15).
This is interesting because the slash command IS the program. There's no setup.py or wizard binary — the markdown drives an LLM to ask the right questions, run the right commands, and write the manifest. The Node script is a small render step at the end.
Summary table
| Surface | Entry point | What runs | What you get |
|---|---|---|---|
| Cowork / Claude Code | claude plugin install <name>@claude-for-financial-services |
Single Claude session reading plugin files | Slash commands, auto-firing skills, named agents, MCP connectors |
| Managed Agents (headless) | scripts/deploy-managed-agent.sh <slug> then client.beta.agents.sessions.steer(...) |
Depth-1 hierarchy: orchestrator + 2-3 subagents on Anthropic infra | Files written to ./out/ per session; orchestrator may emit handoff requests |
| Microsoft 365 add-in setup | /claude-for-msft-365-install:setup |
Interactive Claude session driving an admin through tenant setup | Customized manifest.xml for M365 Admin Center, Azure consent done, optional per-user config |