Ship doctrine and subagents in CE
Epic 10745 "Close the identified gaps in Jaah CE". Original request (verbatim): "Close the identified gaps in Jaah CE". Settled inputs: PRD (Task 10746) and Architecture (Task 10747). Requirement and AC ids below are the PRD's; section refs (§) are the Architecture's. Read them with task_read on 10746/10747 if you need more than is quoted here.
## Requirement (verbatim)
Operator (Q1, Q5, verbatim): "We also need to move some of the md files that are distributed with the package that are essential for proper jaah functionality" → "Runner doctrine, Runner subagents" + "Memory should be excluded as another paid feature". Architect interview: D4 "We are not moving it, it is just a static subset of the same repo"; D5 "We are not removing anything, we are just selecting what will be mirrored to jaah-ce and what not".
R5 — Runner doctrine lives in the product (PRD, verbatim). The md files the dispatch composer needs at runtime ship from a product-owned home inside the shipped tree, not from this management repo's `portfolio/fleet/` and `docs/policies/` paths: `runner-charter.md`, `memory-off.md`, `context-architecture.md`. Single home: one copy only (the management repo points to it; no duplicate). [Realized per D4 as a mirror selection: the monorepo source stays the single home; the tree path is a layout.]
R6 — Memory is paid: `memory-on.md` does not ship (PRD, verbatim). Project memory is a cloud feature in the R2 map; its doctrine file is excluded with it.
R7 — Runner subagents ship with the product (PRD, verbatim). The subagent definitions the product's prompts name are delivered by CE to every runner session: `recon-explore`, `spec-validator`, `back-translator`, `copy-reviewer`, `translation-reviewer`. cto-only agents (`cto-architect`, `cto-code-reviewer`) do not ship.
## Scope and approach
Child C5 of Architecture §7 (Architecture §5). This is a mirror selection: nothing moves (D4/D5).
**Manifest (`tools/community_edition/manifest.toml`).**
- Add `[[layout]]` entries that map into the public tree's product home `doctrine/`:
- `portfolio/fleet/runner-charter.md` → `doctrine/fleet/`
- `portfolio/fleet/memory-off.md` → `doctrine/fleet/`
- `docs/policies/context-architecture.md` → `doctrine/`
- five named includes (no glob), `.claude/agents/{recon-explore,spec-validator,back-translator,copy-reviewer,translation-reviewer}.md` → `doctrine/agents/`
- Drop `portfolio/fleet/memory-on.md` from `include` (R6). If C1 has merged, add it to the `project_memory` row's `paths` instead.
- Do not include `cto-architect.md` or `cto-code-reviewer.md`.
- Confirm `tools/mirror/build.py` supports a single-file layout source mapped to a renamed dir. Extend it (with a test) if not.
- The tree must contain no `portfolio/` and no `docs/policies/`.
**`infra/community-edition/Dockerfile.api:28-29`.** Replace with `COPY doctrine/fleet/ ./doctrine/fleet/` and `COPY doctrine/context-architecture.md ./doctrine/`. DOCTRINE_ROOT is `/app/doctrine` (`system_prompt.py:40-45`), and the CE Dockerfile is only built from the public tree.
**`infra/community-edition/node/stage_bundle.py`.**
- Stage `doctrine/agents/` into the node bundle. Take it from the tree, or from `.claude/agents/` via the manifest when staged from the monorepo (the existing dual-source rule).
- Install `doctrine/context-architecture.md` at the bundle's relative `docs/policies/` location, so the `roles_build.py:425` pointer resolves.
**Claude subagent placement in `apps/jaahd/agents/agent_layer.py` (`place_subagents`).**
- Add a Claude branch guarded by `edition.IS_CE`. This is edition-wide: the CE node is its own harness. C1 pre-lists the site key `apps/jaahd/agents/agent_layer.py::place_subagents` in `EDITION_WIDE`, so keep the guard inside `place_subagents`.
- At dispatch, the branch copies the bundle's `doctrine/agents/*.md` into the Claude account config dir's `agents/`.
- It touches only names it wrote (the existing manifest-of-written-names pattern) and yields to a pre-existing user file of the same name with another hash.
- Use bare names (`recon-explore`), not plugin-namespaced ones.
- Tests: placement, idempotence, user-file yield, cleanup of a removed name.
Cloud delivery (`reconcile.py`, `portable_standard.AGENTS`, `infra/local/Dockerfile.api`) is untouched.
Credentials & reach: (Architecture §10 rows, verbatim)
- Build, check (incl. gitleaks), tooling + app test suites | worktree only; gitleaks at `~/.local/bin/gitleaks` on node h2 | verified (binary present on h2)
- Local CE install from the built tree (AC1.4, AC3.2, AC5.2, AC6.1, AC7.2) | Docker on the coder's node; no registry login (compose `build:` blocks, D3) | verified (`docker` present on h2; C6 re-probes its own node first and, lacking Docker, asks for an h2-class node)
- Jaah Deploy watch per child PR | `jaah-forge` read verbs (`pr checks`, `ci log`) | verified (same forge identity and read probe as above)
Out of scope: (PRD §3, verbatim — do NOT touch)
- MUST NOT make `jaah-ai/jaah-ce` public, change repo visibility, or run a `ce-mirror` publish.
- MUST NOT edit LICENSE text or any legal page (legal review is a human item).
- MUST NOT edit `docs/pricing.md` or the marketing site (deferred to the flip; not in this repo).
- MUST NOT add a second secret scanner (trufflehog etc.).
- MUST NOT add an env var, setting, build arg or runtime flag that selects an edition, enables a feature or moves a cap.
- MUST NOT change cloud behaviour or cloud plan entitlements/pricing; the R2 guard rewrite is behaviour-preserving for `cloud`.
- MUST NOT ship `.claude/skills/` (translate, marketing-copy) — named a deferred follow-up below.
- MUST NOT build an on-prem or enterprise edition — only make the map able to describe one.
Architecture boundaries:
- D4, D5: no monorepo file moves. `portfolio/fleet/*.md`, `docs/policies/context-architecture.md`, `.claude/agents/*.md`, hub pointers, `tools/check_context.py`, `tools/portable_standard.py`, `infra/local/Dockerfile.api` and `infra/host/fleet-harness/reconcile.py` stay untouched.
- D1: keep schema, strip logic. No edition-forked schema, no new migration.
Done means:
- AC5.1 → verify: built tree contains the three files under the product home; `portfolio/` and `docs/policies/` are absent from the tree.
- AC5.2 (image side) → verify: `Dockerfile.api` copies from the product home. The CE api image builds from the built tree (`docker build -f infra/community-edition/Dockerfile.api $T`), and `/app/doctrine/fleet/runner-charter.md` exists in it. (The installed-CE transcript observation, the "Runner Charter" heading in a dispatched task's system prompt, is C6's.)
- AC5.3 → verify: `python3 tools/check_context.py` green in the monorepo (no orphan, no duplicate, every router row resolves).
- AC6.1 (tree side) → verify: built tree has no `memory-on.md`. (The dispatch-content check is C6's.)
- AC7.1 → verify: built tree contains those five definitions under the product home; not the two cto ones.
- jaahd placement tests green:
- a CE-mode dispatch writes the five agent files into the account's `agents/` dir;
- a cloud-mode dispatch writes none;
- a user's own same-named file is left untouched.
- Quick gate `./dc check quick` green.
- `python3 tools/community_edition/build_tree.py $T && python3 tools/community_edition/check_tree.py $T` exits 0 (AC1.2: import closure intact).
- The PR's Jaah Deploy on GitHub succeeds. If not, fix it and re-merge; leave a cancelled or superseded deploy alone.
Outcome
CE tree ships doctrine/ (charter, memory-off, context-arch) + 5 subagents; memory-on and cto agents excluded; Dockerfile.api/stage_bundle use doctrine/; CE Claude placement of subagents. Quick gate, CE suite, image check green; PR #7165 queued. Memory: none applied.
Artifacts
Activity
- Draft
- Ready
- Runner started
- Runner ended (done)