diff --git a/README.md b/README.md index 9f5417b..f080b54 100644 --- a/README.md +++ b/README.md @@ -37,6 +37,7 @@ opinions rather than cloned directly. - `docs/gascity-reference.md` — index of canonical Gas City documentation at `docs.gascityhall.com`, plus the bar for adding new `docs/gascity-*.md` - `docs/gascity-local-patching.md` — recommended process for cities that must carry local `gascity` patches - `docs/file-structure.md` — conventions for where docs and specs live in this pack +- `docs/personas.md` — the persona/agent model: a persona is a skill (identity plus process-skills), and when a persona earns a standing addressable agent ## Usage diff --git a/docs/personas.md b/docs/personas.md new file mode 100644 index 0000000..6f16621 --- /dev/null +++ b/docs/personas.md @@ -0,0 +1,78 @@ +--- +name: Personas +description: How gc-toolkit gives an LLM a role — a persona is a skill (identity plus process-skills), how a persona differs from a standing agent, and the three layers (persona, distribution, Gas City orchestration). +--- + +# Personas (gc-toolkit) + +> How we give an LLM a role. The core is framework-agnostic; Gas City wraps it +> (last section). Mechanics — skill paths, subagent wiring, scoping — are a +> follow-up verified against current Claude Code docs, not assumed. + +## A persona is a skill +Making an LLM *take on a persona* is **loading a skill into its context** — +the universally-adopted skill mechanism already is the persona-loader. A persona is: + +- **Identity** — a tight, always-on stance ("who I am," what I optimize for). + Always loaded; if it's too big to always carry, tighten it. +- **Owns** — advisory: the project-relative artifacts it keeps current + (e.g. docs/architecture.md). Nothing enforces it; the persona honors it. + Promoted to first-class metadata only when a real need appears. +- **Processes** — what it can *do*, each a **skill** of its own + (architect-review), referenced by name. Each process-skill is + self-contained: it bundles its own reference material and declares the files + it reads. There is no separate "references" or "knows" facet — those live + inside the skills that use them. + +No tiering by default — every process is a skill. Add a private/inline process +only when something genuinely can't stand alone. + +The persona-skill *is* the identity plus an index of its method-skills. + +## Identity travels; owns/knows resolve per project +The identity is portable (architect works in any repo). What it owns and +reads is project-relative — the architect maintains *this* repo's +docs/architecture.md, whichever repo it's loaded in. + +## Persona vs. agent +An **agent** is a persona *instantiated as a standing, addressable instance.* +Most persona use is transient — load, work, release. A persona earns a standing +agent only when it must **gate** work or **patrol continuously**; otherwise load +transiently. (In Gas City you bring attention to a *bead*, not an agent, so +"address the architect" mostly dissolves.) + +## Keep skills curated, not global +Every process being a skill does NOT mean every skill loads into every agent — +that would bloat a plain worker with methods it never uses. So: +- a persona's process-skills **ride with the persona**, loaded when engaged; +- only **broadly-shared** methods (red-green) are top-level/always-discoverable; +- a plain worker carries only its minimal set. + +## Three layers +1. **Persona = the skill.** The content; framework-agnostic. +2. **Distribution = a generator.** Renders one canonical persona into each + framework's skill location (.claude/skills/, OpenHands .agents/skills/, ...) + and extracts invokable process-skills. Needed only for >1 target. +3. **Gas City = orchestration.** Which persona onto which bead, owns/knows + resolved per rig, the gc.persona stamp, and the first-pass triage that reads + persona descriptions to assign one to a bare bead. + +## Example + --- + name: architect + description: Use when a change touches system structure, or a PRD needs an + architectural review. + --- + # Architect + ## Who I am + I hold the shape of the system — boundaries, coherence, cost of future change. + ## What I maintain + - docs/architecture.md (advisory) + ## What I do + - review -> the architect-review skill + - design -> the architect-design skill + +## Mechanics (deferred — verify against current docs) +To fill next, against the latest Claude Code / skills docs rather than memory: +where skills load from (flat vs. nested), how subagents consume skills, the +persona-process scoping mechanism, and the assume-persona entry point. diff --git a/specs/tk-oe8o0/README.md b/specs/tk-oe8o0/README.md new file mode 100644 index 0000000..02f116e --- /dev/null +++ b/specs/tk-oe8o0/README.md @@ -0,0 +1,67 @@ +--- +name: Personas model — landing record (tk-oe8o0) +description: Work record for adopting docs/personas.md — the design-session rationale behind the persona/agent model, what landed where, and what was deferred. The lean published doc lives in docs/personas.md; this preserves the fuller reasoning. +--- + +# Personas model — landing record + +This directory is the historical record for **tk-oe8o0**, which adopted the +persona/agent model as a central doc. The authoritative, lean statement is +[`docs/personas.md`](../../docs/personas.md); this record preserves the fuller +design-session rationale and the prior-art that the model draws on. + +## Provenance + +- **Design session:** mechanik-thread, 2026-06-13. The full doc draft and the + architect example were converged there. +- **Status:** operator-blessed 2026-06-13; the prior HELD was lifted. The doc + was landed verbatim as `docs/personas.md`. +- **Builds on:** the shipped bead-universe layer (bead-host / proactive agents, + `mol-first-reaction`, `gc-attention.sh`). +- **Prior art:** five surveys, persisted in full (primary-source write-ups + + provenance) under [`research/`](research/) and indexed by + [`research/prior-art.md`](research/prior-art.md), so adopted patterns stay + auditable from the repo alone. + +## The model (lean) — design rationale + +The published doc is the lean form. The reasoning that produced it: + +- **A persona IS a skill.** "Take on a persona" = load the skill. + Framework-agnostic. +- **A persona = tight always-on IDENTITY + advisory OWNS + PROCESSES**, each a + skill. References/knows fold INTO the process-skills (self-contained). No + tiering by default; private/inline process only when required. +- **Identity is portable**; owns/knows resolve per deployment rig. +- **An AGENT = a persona instantiated as a standing/addressable instance** — + earned only to GATE work or PATROL continuously; else transient load. +- **Curate skills per consumer (NOT global):** a persona's process-skills ride + with the persona; only broadly-shared methods go top-level; a plain polecat + stays minimal. (Avoids skill-bloat on simple workers.) +- **Three layers:** (1) persona = the skill; (2) distribution = a generator + renders the canonical persona into each framework's skill location + extracts + process-skills (only for >1 target); (3) Gas City orchestration = + persona↔bead binding, rig-relative owns/knows, the `gc.persona` stamp, and the + first-pass triage. + +## Landing decisions + +- **Adopted verbatim** as `docs/personas.md` (with the conventional + `name`/`description` frontmatter the file-structure spec asks of central + docs). +- **Discoverability:** the root `README.md` "Docs" list now points at + `docs/personas.md`, per the file-structure adoption guidance (update the + discoverability surface in the same PR). +- **Mechanics deferred.** The doc keeps a `## Mechanics (deferred)` stub. Filling + it is a separate follow-up that must run a latest-knowledge verification pass + (claude-code-guide / current Claude Code docs) covering skill load paths (flat + vs. nested), subagent skill consumption, persona-process scoping, and the + assume-persona entry point. It was deliberately NOT filled here. + +## Cross-cutting takeaway from the prior art + +The identity/owns split is validated prior art (CrewAI, MetaGPT). Treating +"owns" as a maintained-artifact contract is novel — no surveyed system has it. +The knows-inclusion idea is borrowable from Kiro/Cursor. And persona-adoption == +skill-loading is the load-bearing observation: it is *why* a persona is a skill. +See [`research/prior-art.md`](research/prior-art.md) for the sourced surveys. diff --git a/specs/tk-oe8o0/research/prior-art.md b/specs/tk-oe8o0/research/prior-art.md new file mode 100644 index 0000000..29bbcdf --- /dev/null +++ b/specs/tk-oe8o0/research/prior-art.md @@ -0,0 +1,78 @@ +--- +name: Personas prior-art surveys (provenance) +description: Provenance-stamped index of the five prior-art surveys behind the persona/agent model — the systems surveyed, what each contributed, and sources — so the patterns adopted into docs/personas.md stay auditable. +--- + +# Prior-art surveys — provenance + +Five prior-art surveys informed the persona/agent model adopted in +[`docs/personas.md`](../../../docs/personas.md). This file is the +**provenance-stamped index**: the systems surveyed, the pattern each +contributed, and the sources. The full survey write-ups — produced in the +mechanik-thread design session (2026-06-13) from primary sources — are +persisted alongside this index as `survey-N-*.md` and linked under each +heading below, so the adopted patterns stay auditable from the repo alone. + +## 1. OpenHands / OpenClaw + +**Full survey:** [`survey-1-openhands-openclaw.md`](survey-1-openhands-openclaw.md) + +OpenHands microagents and OpenClaw's `IDENTITY.md` + `SOUL.md` split, plus a +heartbeat daemon for a standing agent. + +- [OpenHands docs](https://docs.openhands.dev) +- [OpenClaw docs](https://docs.openclaw.ai) +- [openclaw/openclaw](https://github.com/openclaw/openclaw) + +## 2. MetaGPT / ChatDev + +**Full survey:** [`survey-2-metagpt-chatdev.md`](survey-2-metagpt-chatdev.md) + +MetaGPT's `Role` class (SOP-as-actions, path-constants × `ProjectRepo`) and +ChatDev's `RoleConfig` / `PhaseConfig` / `ChatChain`. + +- [FoundationAgents/MetaGPT](https://github.com/FoundationAgents/MetaGPT) +- [OpenBMB/ChatDev](https://github.com/OpenBMB/ChatDev) + +## 3. CrewAI / AutoGen / LangGraph + +**Full survey:** [`survey-3-crewai-autogen-langgraph.md`](survey-3-crewai-autogen-langgraph.md) + +CrewAI's `Agent` (role / goal / backstory, output declared on the `Task`), +AutoGen's `system_message` vs `description` split, and LangGraph's nodes + +reducers. + +- [CrewAI docs](https://docs.crewai.com) +- [AutoGen docs](https://microsoft.github.io/autogen) +- [LangGraph docs](https://docs.langchain.com/langgraph) + +## 4. Roo Code / Cline / Cursor / Aider + +**Full survey:** [`survey-4-roo-cline-cursor-aider.md`](survey-4-roo-cline-cursor-aider.md) + +Roo Code custom modes (`fileRegex` edit-fence), Cline, Cursor inclusion modes, +and Aider's read-only vs. editable file distinction. + +- [Roo Code docs](https://docs.roocode.com) +- [Cline docs](https://docs.cline.bot) +- [Cursor docs](https://docs.cursor.com) +- [Aider](https://aider.chat) + +## 5. Claude Code / Kiro / Amazon Q + +**Full survey:** [`survey-5-claude-kiro-amazonq.md`](survey-5-claude-kiro-amazonq.md) + +Claude Code subagents + skills, Kiro steering (inclusion: always / fileMatch / +manual), and Amazon Q resources globs. + +- [Claude Code docs](https://code.claude.com/docs) +- [Kiro docs](https://kiro.dev/docs) +- [Amazon Q docs](https://docs.aws.amazon.com) + +## Key cross-cutting findings + +- The **identity / owns split** is validated prior art (CrewAI, MetaGPT). +- Treating **"owns" as a maintained-artifact contract** is novel — no surveyed + system has it. +- **Knows-inclusion** is borrowable from Kiro / Cursor. +- **Persona-adoption == skill-loading** — this is *why* a persona is a skill. diff --git a/specs/tk-oe8o0/research/survey-1-openhands-openclaw.md b/specs/tk-oe8o0/research/survey-1-openhands-openclaw.md new file mode 100644 index 0000000..d99ad04 --- /dev/null +++ b/specs/tk-oe8o0/research/survey-1-openhands-openclaw.md @@ -0,0 +1,97 @@ +--- +name: Prior-art survey 1 — OpenHands & OpenClaw +description: Full primary-source survey behind the persona model — OpenHands microagents/skills (keyword triggers, repo.md, public registry) and OpenClaw's factored IDENTITY.md / SOUL.md bootstrap bundle plus heartbeat daemon. Persisted from the mechanik-thread design session (2026-06-13); indexed by prior-art.md. +--- + +# Persona-System Prior Art Survey: OpenHands & OpenClaw + +## Provenance + +| System | Mechanism / artifact | Source (URL + repo/path) | Surveyed at | +|---|---|---|---| +| OpenHands microagents (V0 layout) | `.openhands/microagents/` — `repo.md` + keyword-triggered `*.md` | https://docs.openhands.dev/usage/prompting/microagents-repo ; https://docs.openhands.dev/usage/prompting/microagents-keyword ; dir listing `github.com/All-Hands-AI/OpenHands/tree/main/.openhands/microagents` | 2026-06-13 | +| OpenHands Skills (V1, supersedes microagents) | `.agents/skills//SKILL.md`; legacy `.openhands/{microagents,skills}/` read for back-compat | https://docs.openhands.dev/usage/prompting/microagents-overview (redirect from docs.all-hands.dev) | 2026-06-13 | +| OpenHands public registry | `skills//SKILL.md`, `plugins/`, distributed via `@openhands/extensions` | https://github.com/OpenHands/skills | 2026-06-13 | +| OpenDevin lineage | Renamed → OpenHands (early 2025), maintained by All-Hands-AI | https://arxiv.org/abs/2407.16741 ; https://www.openhands.dev/blog/one-year-of-openhands-a-journey-of-open-source-ai-development | 2026-06-13 | +| OpenClaw | Bootstrap files `IDENTITY.md` / `SOUL.md` / `AGENTS.md` / `USER.md` / `TOOLS.md` / `BOOTSTRAP.md`; `SKILL.md` skills | https://docs.openclaw.ai/concepts/agent ; https://github.com/openclaw/openclaw ; https://www.freecodecamp.org/news/how-to-build-and-secure-a-personal-ai-agent-with-openclaw/ | 2026-06-13 | + +**Honesty notes up front:** +- **OpenClaw is real**, not a misremembering. Repo `github.com/openclaw/openclaw`, docs at `docs.openclaw.ai`. Lineage: **Moltbot → Clawdbot → OpenClaw** (recent renames; no firm dates published — URLs still carry old names). I did **not** independently verify the "378k stars / fastest-growing repo" figures (came from a fetched page summary; treat as marketing). +- **OpenHands terminology has shifted.** "Microagents" is the **V0** name; **V1 renamed them "Skills"** and moved the canonical path to `.agents/skills/`. The `.openhands/microagents/` path you asked about still works (back-compat) but is **legacy**. I report the microagents model as asked and flag where V1 differs. +- The OpenHands `.openhands/microagents/repo.md` was **not** at that exact path on `main` when checked — the live dir now holds `documentation.md` + `glossary.md`. `repo.md` is the documented convention and exists in many repos, but the canonical self-hosted example has been reorganized. Don't assume a fixed filename on HEAD. +- I could **not** load the V1 `SKILL.md` full schema page (404) or the Stanza IDENTITY.md course page (403). Field lists for those are corroborated across secondary sources, flagged inline. + +--- + +## 1. OpenHands microagents (`.openhands/microagents/`) + +This is really **three sub-mechanisms** under one directory. I'll split where the model differs. + +### 1a. Repository microagent (`repo.md`) +- **Definition format:** Markdown; YAML frontmatter **optional**. If present, supports an `agent` field (defaults to `CodeActAgent`). No frontmatter → loaded as the repo agent with defaults. +- **Portable identity (a):** **No.** This is the *anti-persona* — it is entirely project-specific by design (repo purpose, setup commands, dir structure, CI checks, dev guidelines). It travels with the *repo*, not with a role. +- **Owned/managed files (b):** **No.** Purely informational context; it does not declare artifacts it writes nor restrict which files may be edited. (The closest thing: OpenHands *instructs the agent* to **create** an `AGENTS.md` at repo root — but `repo.md` itself isn't a file-ownership contract.) +- **Known/context files (c):** Implicit only — it *is* the curated context. No declared input globs. +- **Processes (d):** Soft — embeds setup/build/test conventions as prose, not a bound workflow engine. +- **Instantiation:** **Always loaded** into context for that repo; transient (prompt injection, not a standing addressable agent). +- **Closeness to our model:** Low — it's the project-pinned (b/c) half with **zero** portable identity. +- **Worth borrowing:** The "always-on, repo-resolved context file the agent both *reads and is told to maintain*" is a clean precedent for your *owns* + *knows* resolved-per-deployment. + +### 1b. Knowledge (keyword-triggered) microagents +- **Definition format:** Markdown + **required** YAML frontmatter. Confirmed fields: `name`, `description`, `triggers` (list of keywords). (V0 also documented a `type: knowledge` / `agent` field across versions.) +- **Portable identity (a):** **Yes — strongest match here.** These are explicitly "reusable across multiple projects," domain expertise (e.g. a `github`/`git` agent) that travels independent of any one repo. This is the "portable identity/knowledge" leg of your model. +- **Owned/managed files (b):** No. +- **Known/context files (c):** **No file-glob/fileMatch.** Verified: activation is **keyword-in-prompt only** — there is **no** filesystem/file-type-based conditional loading in the docs. (Some marketing copy claims "context-aware based on file types"; the primary docs do **not** support that — honest flag.) +- **Processes (d):** Encodes methods/SOPs as triggered prose. +- **Instantiation:** Transient, **lazy** — loaded only when a trigger keyword appears. Not addressable. +- **Closeness to our model:** Medium-high on (a)+(d); misses (b) and (c-as-glob). +- **Worth borrowing:** **Trigger-gated lazy loading** is exactly your "loaded transiently into a conversation/step." Borrow the `triggers:` frontmatter as a cheap activation gate — but note its weakness (keyword-only) and consider adding the file-glob *knows* dimension they lack. + +### 1c. Task microagents (`pr_review.md`, `bug_fix.md`, `feature.md`) +- Workflow templates (the *processes* leg). Documented as present but not formally schema'd as a distinct type. Maps to your (d). + +**V1 delta (Skills):** Same model, renamed. Canonical path `.agents/skills//SKILL.md` (+ optional `README.md`); user-level `~/.agents/skills/`; categories are **Permanent/Repository, Keyword-Triggered, Organization, Global**. "AgentSkills-style progressive disclosure." Public registry (`OpenHands/skills`, npm `@openhands/extensions`) gives a real **portable-persona distribution channel** — directly relevant to your "travels-with-it" leg. + +--- + +## 2. OpenDevin (lineage) + +Not a separate mechanism — **OpenDevin is the former name of OpenHands** (homage to Cognition's Devin; renamed early 2025; now All-Hands-AI). The microagents/skills system is OpenHands-era; surveying OpenDevin separately would be redundant. Honest note: I found **no** distinct "OpenDevin persona" artifact predating the OpenHands microagents design. + +--- + +## 3. OpenClaw (the "identity.md" recollection — **confirmed real**) + +Your operator's memory is accurate. OpenClaw uses a **bootstrap-file bundle** that is the closest whole-system analog to your persona model. + +- **Definition format:** A workspace dir (`~/.openclaw/workspace/`) of **plain Markdown** bootstrap files, injected into the system prompt's "Project Context" on the first turn of a session. Blank files skipped; missing files leave a marker; `openclaw setup` scaffolds defaults. Config in `openclaw.json` (`agents.defaults.workspace`, etc.). Skills are `SKILL.md` folders with YAML frontmatter (`name`, `description`), loaded **on-demand**. +- **Portable identity (a):** **Yes — and explicitly *factored*.** This is the standout: identity is split across files by concern — + - `IDENTITY.md` = **factual identity** (name, vibe, emoji; ~5–15 lines), + - `SOUL.md` = **persona/boundaries/tone** ("what you do / what you never do / how you communicate"), + - `AGENTS.md` = operating instructions/memory rules, + - `USER.md` = user profile, + - `TOOLS.md` = tool guidance, + - `BOOTSTRAP.md` = one-time first-run ritual (self-deletes). + Because it's all on-disk Markdown, copying the workspace ports the persona (portability is implied, not a first-class "travels-with-it-across-projects" abstraction — honest caveat). +- **Owned/managed files (b):** Partial — `MEMORY.md` + `memory/` daily logs are artifacts the agent **maintains**; `AGENTS.md` codifies memory/bill-tracking write rules. No formal "this persona may only edit X" restriction. +- **Known/context files (c):** The bootstrap bundle + `MEMORY.md` are declared, always-injected inputs. `HEARTBEAT.md` is the periodic checklist read on daemon wakeups. No glob/fileMatch inclusion. +- **Processes (d):** `AGENTS.md` (SOPs/safety rails, e.g. "always screenshot after filling a form"), `HEARTBEAT.md` (patrol checklist), `cron/jobs.json`, and `SKILL.md` skills. +- **Instantiation:** **Standing daemon** — one embedded agent per Gateway (`systemd`/`LaunchAgent`, `openclaw gateway`, default `ws://127.0.0.1:18789`), wakes on heartbeat (~30 min). **Addressable** via stable session IDs (JSONL sessions); supports mid-run queue modes (`/queue steer|followup|collect|interrupt`). +- **Closeness to our model:** **Highest of all surveyed.** It hits a (factored identity), partial b (maintained memory), c (declared context), d (SOPs + heartbeat + skills) — the main divergence from yours is **always-standing daemon** vs your **transient-by-default, standing-only-to-patrol**. (And OpenClaw's heartbeat = "patrol continuously" is precisely your standing-agent case.) +- **Worth borrowing:** The **multi-file identity factoring** — `IDENTITY.md` (terse facts) vs `SOUL.md` (persona/tone) vs `AGENTS.md` (operating rules) — is the single best idea to steal: it lets the *portable* core (identity+soul) stay clean while project/operational concerns live in separate, separately-resolved files. Also borrow `HEARTBEAT.md` as the explicit artifact that distinguishes "transient load" from "standing patrol." + +--- + +## Synthesis for your model + +| Your leg | Best precedent | Gap to mind | +|---|---|---| +| **(a) portable identity** | OpenClaw `IDENTITY.md`+`SOUL.md` (factored); OpenHands knowledge skills (reusable, registry-distributed) | OpenClaw doesn't abstract "across projects" first-class; OpenHands repo.md is the opposite (project-pinned) | +| **(b) owns (project-relative artifacts written)** | OpenClaw `MEMORY.md`/memory logs; OpenHands "create AGENTS.md" instruction | **Neither declares a write-scope/edit-restriction contract** — this is genuinely novel to your model; nobody surveyed restricts editable files per persona | +| **(c) knows (project-relative context read)** | OpenHands repo.md (always-on); OpenClaw bootstrap bundle | **No system supports glob/`fileMatch` context inclusion** — verified absent in OpenHands (keyword-only). Your per-deployment glob resolution is a differentiator | +| **(d) processes** | OpenHands task microagents + `triggers`; OpenClaw `AGENTS.md`/`HEARTBEAT.md`/skills | Well-trodden; lazy keyword-triggering is the cheap-win pattern | +| **instantiation (transient↔standing)** | OpenHands = transient/lazy injection; OpenClaw = standing daemon + heartbeat + addressable sessions | You want **both modes in one model** — neither system spans the full range; OpenClaw's session-ID addressability + queue-steer is a good standing-mode reference | + +**Two things no surveyed system does that your model proposes** (so: green-field, verify you actually want the complexity): (1) **per-persona editable-file/owned-artifact scoping** (b as a contract, not just convention), and (2) **glob/`fileMatch`-based "knows" inclusion** resolved per deployment. The closest anyone gets to (c) is keyword triggers (OpenHands) and always-on bundles (both). + +Sources: [OpenHands repo microagent docs](https://docs.openhands.dev/usage/prompting/microagents-repo), [OpenHands keyword skills docs](https://docs.openhands.dev/usage/prompting/microagents-keyword), [OpenHands skills overview](https://docs.openhands.dev/usage/prompting/microagents-overview), [OpenHands public skills registry](https://github.com/OpenHands/skills), [OpenHands `.openhands/microagents/` dir](https://github.com/All-Hands-AI/OpenHands/tree/main/.openhands/microagents), [OpenHands arXiv paper](https://arxiv.org/abs/2407.16741), [One Year of OpenHands](https://www.openhands.dev/blog/one-year-of-openhands-a-journey-of-open-source-ai-development), [OpenClaw agent runtime docs](https://docs.openclaw.ai/concepts/agent), [openclaw/openclaw repo](https://github.com/openclaw/openclaw), [freeCodeCamp OpenClaw guide](https://www.freecodecamp.org/news/how-to-build-and-secure-a-personal-ai-agent-with-openclaw/). diff --git a/specs/tk-oe8o0/research/survey-2-metagpt-chatdev.md b/specs/tk-oe8o0/research/survey-2-metagpt-chatdev.md new file mode 100644 index 0000000..ab0a5b5 --- /dev/null +++ b/specs/tk-oe8o0/research/survey-2-metagpt-chatdev.md @@ -0,0 +1,80 @@ +--- +name: Prior-art survey 2 — MetaGPT & ChatDev +description: Full primary-source survey — MetaGPT's Role class (typed identity fields, SOP-as-actions, path-constants × ProjectRepo, _watch/cause_by typed handoff) and ChatDev's RoleConfig / PhaseConfig / ChatChain JSON split. Persisted from the mechanik-thread design session (2026-06-13); indexed by prior-art.md. +--- + +# Persona-System Prior Art: MetaGPT & ChatDev + +## Provenance + +| System | Mechanism / artifact | Source (URL + repo/path) | Surveyed at | +|---|---|---|---| +| MetaGPT | `Role` base class (identity fields) | `FoundationAgents/MetaGPT@main` · [`metagpt/roles/role.py`](https://github.com/FoundationAgents/MetaGPT/blob/main/metagpt/roles/role.py) | 2026-06-13 | +| MetaGPT | Concrete roles (PM / Architect / Engineer / QA) | `metagpt/roles/{product_manager,architect,engineer,qa_engineer}.py` | 2026-06-13 | +| MetaGPT | Artifact path constants (owned files) | [`metagpt/const.py`](https://github.com/FoundationAgents/MetaGPT/blob/main/metagpt/const.py) (`PRDS_FILE_REPO="docs/prd"`, etc.) | 2026-06-13 | +| MetaGPT | SOP as actions | `metagpt/actions/{write_prd,design_api,project_management,write_code,write_test}.py` | 2026-06-13 | +| MetaGPT | Paper (SOP-as-prompt thesis) | [arXiv 2308.00352](https://arxiv.org/html/2308.00352v6) | 2026-06-13 | +| ChatDev (classic "chat chain") | `RoleConfig.json` / `PhaseConfig.json` / `ChatChainConfig.json` | `OpenBMB/ChatDev@chatdev1.0` · [`CompanyConfig/Default/*.json`](https://github.com/OpenBMB/ChatDev/tree/chatdev1.0/CompanyConfig/Default) | 2026-06-13 | +| ChatDev (classic) | Phase / ComposedPhase / ChatChain engine | `chatdev/{phase,composed_phase,chat_chain,chat_env}.py` (branch `chatdev1.0`) | 2026-06-13 | +| ChatDev 2.0 (current `main`) | Graph/node config rewrite (NOT the chat chain) | `OpenBMB/ChatDev@main` · `entity/configs/node/agent.py`, `graph_config.py` | 2026-06-13 | + +**Caveat worth flagging up front:** ChatDev's repo `main` was rewritten into a 2.0 "graph of nodes" zero-code platform; the classic role/phase/chat-chain design the question targets now lives on branch **`chatdev1.0`** (and tags ≤ v1.1.6). I surveyed `chatdev1.0` as primary. Everything below is from primary source files; where a fetch summary gave a shaky count I say so rather than assert it. + +--- + +## MetaGPT + +**Definition format.** Python class. Each role subclasses `Role` (a Pydantic `BaseModel`); newer ones subclass `RoleZero` (which subclasses `Role`). Identity is **class attributes**; behavior is wired in `__init__` via method calls. E.g. `ProductManager(RoleZero)` sets `name="Alice"`, `profile="Product Manager"`, `goal="Create a Product Requirement Document..."`, `constraints="utilize the same language as the user requirements..."`. + +**Portable identity (your `a`).** Strong and explicit. `Role` defines `name`, `profile`, `goal`, `constraints`, `desc` — all **project-agnostic strings** baked into the class, injected into the LLM system prompt. They carry zero project specifics (no paths, no IDs); the same class drops into any run. This is close to your "portable identity that travels with the persona." + +**Owned/managed files (your `b`).** Yes, but **indirectly** — ownership is expressed as *which Action a role runs*, and the Action writes to a **fixed, project-relative path constant** in `const.py`, resolved under the active `ProjectRepo` (the deployment root). So: +- ProductManager → `WritePRD` → `PRDS_FILE_REPO = "docs/prd"` +- Architect → `WriteDesign` → `SYSTEM_DESIGN_FILE_REPO = "docs/system_design"` (+ `resources/data_api_design`, `resources/seq_flow`) +- ProjectManager → `WriteTasks` → `TASK_FILE_REPO = "docs/task"` +- Engineer → `WriteCode` → source tree via `self.repo.srcs.save()`; summaries to `docs/code_summary` +- QAEngineer → `WriteTest`/`RunCode`/`DebugError` → `tests/`, `test_outputs/` + +The role doesn't *declare* "I own `docs/prd`" in its own body — the binding is `role → action → path-constant`, paths globally defined and re-rooted per deployment via `ProjectRepo`. Functionally equivalent to your "owns project-relative artifacts, resolved per deployment," but the declaration is split across three files, not co-located on the persona. + +**Known/context files (your `c`).** Expressed as **action-level subscriptions, not file inputs.** A role calls `self._watch([...Action types...])`; it then consumes the *messages those actions emitted* (each `Message` carries `cause_by`). Architect `_watch({WritePRD})`; Engineer `_watch({WriteTasks, SummarizeCode, WriteCode, WriteCodeReview, FixBug, WriteCodePlanAndChange})`. So "knows" = "the upstream artifacts named by the actions I watch," dereferenced through the shared repo — typed by *producing action*, not by literal path. + +**Processes (your `d`).** This is MetaGPT's thesis: **SOP encoded as prompts.** Each role's method is a sequence of `Action` objects (`set_actions([...])`), and reaction strategy is declared (`rc.react_mode`: `REACT` think-act loop, `BY_ORDER` sequential, or `PLAN_AND_ACT`). The PM runs `[PrepareDocuments, WritePRD]` `BY_ORDER`. The Action subclass holds the structured prompt + an output schema (`WritePRD` demands Product Goals, User Stories, Competitive Analysis, Requirement Pool). The paper frames the whole system as "SOPs encoded as prompt sequences," with two parts: *role specialization* + *workflow across agents*. + +**Instantiation.** **Standing and addressable** within a run. Roles are long-lived objects hired into a `Team`/`Environment` (`company.hire([ProductManager(), Architect(), ProjectManager(), Engineer()])`), each with a personal message buffer, addressed via `name`/`addresses` routing tags. They idle until a watched message arrives, then react. Handoff = publish a message tagged by `cause_by`; the downstream role's `_watch` picks it up — a **typed pub/sub over a shared file repo**, not direct calls. This differs from your "loaded transiently, becomes standing only to gate/patrol" — MetaGPT roles are standing by default for the whole job. + +**Closeness to your model:** High — clean separation of portable identity (class attrs) from per-deployment artifacts (path-constants × `ProjectRepo`), with explicit owns/knows/process. +**Worth borrowing:** The `role → action → path-constant`-rooted-at-deployment indirection (your "owns, resolved per deployment") and **typed artifact handoff via `cause_by` + `_watch`** instead of free-form chat — directly models your owns/knows as a producer/consumer graph. + +--- + +## ChatDev (classic "chat chain", branch `chatdev1.0`) + +**Definition format.** **JSON config, not code.** Three decoupled files under `CompanyConfig//`: `RoleConfig.json` (who), `PhaseConfig.json` (how, per step), `ChatChainConfig.json` (order). Agents are instantiated by the engine (`chatdev/role_play` via the CAMEL `RolePlaying` substrate) from these configs — you customize a "company" by editing JSON, no subclassing. + +**Portable identity (your `a`).** Present but **thin and prompt-only.** `RoleConfig.json` maps each role name → an **array of prompt strings** (the role's "inception" system prompt). The default ships 9 roles: Chief Executive Officer, Chief Product Officer, Counselor, Chief Technology Officer, Chief Human Resource Officer, Programmer, Code Reviewer, Software Test Engineer, Chief Creative Officer. Example (CEO) literally: `["{chatdev_prompt}", "You are Chief Executive Officer. Now, we are both working at ChatDev...", "Your main responsibilities include being an active decision-maker...", "Here is a new customer's task: {task}.", ...]`. It *is* portable (project enters only via `{task}`/`{modality}` placeholders), but identity = a static prompt blob with **no goal/constraints schema, no knowledge beyond the prose**. Weaker and less structured than your "core role/knowledge" or MetaGPT's typed fields. + +**Owned/managed files (your `b`).** **Not declared per role.** Roles don't own artifacts. Artifacts (code, manual, requirements, env doc) accumulate in a shared mutable blackboard — `ChatEnv` (`chatdev/chat_env.py`) — and are flushed to a single project directory. No `architect → architecture.md` style ownership binding exists; *phases* mutate shared state, roles don't hold files. This is the **biggest divergence** from your model: ChatDev has no per-persona owned-artifact concept. + +**Known/context files (your `c`).** **Not declared.** A phase reads from and writes to the shared `ChatEnv` (whole prior code/requirements/designs in scope as prompt context); there's no per-role declared input set. "Knowledge" is whatever the phase prompt template injects via placeholders (`{task}`, `{description}`, `{modality}`, `{language}`, `{ideas}`, `{gui}`, `{codes}`, `{unimplemented_file}`). + +**Processes (your `d`).** **The strongest, most explicit part — but it lives on the *phase/chain*, not the persona.** Process is a two-level pipeline: +- `ChatChainConfig.json` → ordered `chain`: `DemandAnalysis → LanguageChoose → Coding → CodeCompleteAll → CodeReview → Test → EnvironmentDoc → Manual`. Each entry has `phaseType` (`SimplePhase` = one dialogue, or `ComposedPhase` = looped, e.g. `CodeReview` cycleNum 3, `Test` cycleNum 3, `CodeCompleteAll` cycleNum 10), `max_turn_step`, `need_reflect`. +- `PhaseConfig.json` → each phase binds **exactly two roles** (`assistant_role_name`, `user_role_name`) + a `phase_prompt` template. E.g. `Coding`: assistant `Programmer`, user `Chief Technology Officer`. The SOP is the *sequence of two-agent role-plays*, not a method attached to any one agent. + +**Instantiation.** **Transient and pairwise.** No standing addressable roster — for each phase the engine spins up a CTO↔Programmer (etc.) `RolePlaying` dialogue, runs ≤`max_turn_step` turns (optionally a `Counselor`↔`CEO` *reflection* sub-chat), writes results to `ChatEnv`, and tears the pairing down. Roles are summoned per phase. Handoff is **implicit via shared `ChatEnv` state** advanced by the chain — not messages, not typed subscriptions. This is *closer* to your "loaded transiently" intuition than MetaGPT, but there's no "becomes standing to gate/patrol" path at all. + +**Closeness to your model:** Moderate-low — excellent declarative *process* (chain/phase) and portable-ish prompt identity, but **no owns/knows per persona** (artifacts live on a shared blackboard) and roles are transient phase-pairings. +**Worth borrowing:** The **3-file split (identity / step-method / ordering)** and especially the **`ComposedPhase` loop primitive** (`cycleNum`, reflection) — a clean, data-driven way to express your "processes" and the "gate work / patrol continuously" iterative-review modes without code. + +--- + +## Cross-cutting read for your design + +- **Identity (`a`):** Both keep identity project-agnostic and prompt-injected. MetaGPT's *typed* fields (`profile`/`goal`/`constraints`) are the better template for "portable identity + core knowledge" than ChatDev's prose blob. +- **Owns (`b`):** Only MetaGPT has anything like it, and it's **emergent** (`role → action → path-constant`, re-rooted by `ProjectRepo`) rather than a first-class `owns:` declaration on the persona. **Neither system has your clean "persona declares the project-relative artifacts it maintains."** That's a genuine gap your model fills — worth making first-class. +- **Knows (`c`):** Neither declares file inputs literally. MetaGPT types inputs by *producing action* (`_watch` + `cause_by`); ChatDev gives whole shared state. MetaGPT's typed-producer approach is the more borrowable basis for declared inputs. +- **Processes (`d`):** MetaGPT binds method **to the persona** (`set_actions` + `react_mode`); ChatDev binds it **to the pipeline** (chain + phase JSON). Your "processes it applies" leans MetaGPT-shaped (per-persona), but ChatDev's externalized chain is the better model if you want the *workflow* to be reconfigurable independent of personas. +- **Instantiation (`b`/standing-vs-transient):** Your "transient by default, standing only to gate/patrol" matches **neither** cleanly — MetaGPT roles are standing-for-the-run; ChatDev roles are transient phase-pairings with no standing mode. Your hybrid (transient load + promotable to addressable gatekeeper/patrol) is novel relative to both. + +**Honesty notes:** PhaseConfig key count came back ambiguous (12 vs 13 in fetch summaries) — I report only the chain-level phase order, which I verified directly, and don't assert an exact PhaseConfig key count. Concrete-role file contents (PM/Architect/Engineer) are verified from source; the QA role's exact attrs I inferred from the established `_watch`/`set_actions` pattern + action filenames rather than a full file read, so treat QA specifics as pattern-level, not line-verified. diff --git a/specs/tk-oe8o0/research/survey-3-crewai-autogen-langgraph.md b/specs/tk-oe8o0/research/survey-3-crewai-autogen-langgraph.md new file mode 100644 index 0000000..0426cb1 --- /dev/null +++ b/specs/tk-oe8o0/research/survey-3-crewai-autogen-langgraph.md @@ -0,0 +1,64 @@ +--- +name: Prior-art survey 3 — CrewAI, AutoGen & LangGraph +description: Full primary-source survey — CrewAI's Agent/Task identity-vs-output split, AutoGen's system_message vs description two-field identity, and LangGraph's reducers as artifact-ownership contracts. Persisted from the mechanik-thread design session (2026-06-13); indexed by prior-art.md. +--- + +# Persona-System Prior-Art Survey: CrewAI, AutoGen, LangGraph + +## Provenance + +| System | Mechanism / artifact | Source (URL + repo/path) | Surveyed at | +|---|---|---|---| +| CrewAI | `Agent` (role/goal/backstory/tools) + `Task` (output_file/output_pydantic/context) | docs.crewai.com/en/concepts/agents ; .../concepts/tasks ; repo `crewAIInc/crewAI` | 2026-06-13 | +| Microsoft AutoGen | `ConversableAgent`/`AssistantAgent` — `system_message` + `description` (v0.2); v0.4 `autogen_agentchat.agents` | microsoft.github.io/autogen/0.2/docs/reference/agentchat/conversable_agent ; .../stable/reference/python/autogen_agentchat.agents.html ; repo `microsoft/autogen` | 2026-06-13 | +| LangGraph | `StateGraph` nodes (functions) + `Annotated`/reducers; prebuilt `create_react_agent` → `create_agent` | docs.langchain.com/oss/python/langgraph/graph-api ; reference.langchain.com/python/langgraph.prebuilt/.../create_react_agent | 2026-06-13 | + +**Verification honesty:** CrewAI raw source files (`src/crewai/agent.py` etc.) returned 404 to raw fetch (repo restructured/blocked), so CrewAI field-level claims rest on the official docs attribute tables, not the class source. AutoGen v0.2 reference is legacy-but-canonical; I cross-checked the current v0.4 `autogen_agentchat` reference and note where they diverge. LangGraph prebuilt page moved; `create_react_agent` params confirmed from the LangChain API reference, which also flags its deprecation in favor of `create_agent`. + +--- + +## CrewAI — `Agent` + +- **Definition format:** Both a Python class (`Agent(...)`) and a declarative `agents.yaml` schema (recommended), wired via `@agent`/`@CrewBase` decorators where YAML method names must match Python. +- **Portable identity:** **Yes, strong.** `role`, `goal`, `backstory` are required identity fields; `tools`, `llm`, `memory`, `knowledge_sources`, `embedder`, and prompt templates are optional. The Agent is defined independently of any task and composed into a crew by reference — the closest analog to your "portable identity" of the three. +- **Owned/managed files:** **No — and this is the key finding.** Output ownership lives on the **`Task`**, not the Agent: `output_file`, `output_json`, `output_pydantic`, `create_directory`, `markdown`, `guardrail`. The Task binds a worker via its `agent` field. So "who I am" and "what I emit" are split across two objects. +- **Known/context files:** Partially at the Agent level via `knowledge_sources` (declared readable knowledge) + `embedder`/RAG tools. Task-to-task inputs are declared on the Task via `context` (list of upstream Tasks), not on the Agent. +- **Processes:** Indirect. The Agent does not enumerate its methods; `Task`s reference the Agent, and the crew's `process` (sequential/hierarchical) drives execution. +- **Instantiation:** Mostly transient/composed, but addressable: `Agent.kickoff()` lets an agent run directly without a task/crew, and `memory` gives it persistence within a crew. Not a long-lived network-addressable service. +- **Closeness to our model:** Closest overall — explicit reusable role identity, declared knowledge inputs, transient-by-default with a direct-invoke escape hatch. +- **Worth borrowing:** The **identity/output split** (persona = portable role; *owns* artifacts declared elsewhere and resolved per deployment) — CrewAI independently arrived at exactly your (a)-vs-(b) separation by putting `output_file` on Task, not Agent. + +--- + +## Microsoft AutoGen — `ConversableAgent` / `AssistantAgent` + +- **Definition format:** Python class instantiation. `ConversableAgent(name=..., system_message=..., description=..., llm_config=...)`; `AssistantAgent`/`UserProxyAgent` are subclasses with preset defaults. (v0.4 AgentChat: same shape, `model_client` replaces `llm_config`.) +- **Portable identity:** **Yes, but prose-only.** Identity is the free-text `system_message` ("You are a helpful AI Assistant." by default). It is reusable and task-independent, but unstructured — no role/goal/backstory decomposition. Notably AutoGen splits identity into **two fields**: `system_message` (steers the model) and `description` (a short capability blurb other agents/the `GroupChatManager` read to decide *when to call this agent*). That description field is a clean analog to a persona's externally-advertised, addressable interface. +- **Owned/managed files:** **No.** No owned-output declaration. Code-execution agents reference a `work_dir`, but that's executor config, not an agent-level artifact contract. +- **Known/context files:** **No declared file inputs.** Context enters as conversation history (`chat_messages`/carryover), not as declared context files. +- **Processes:** Strong, but conversational rather than artifact-based. Behavior binds via `register_reply` (trigger→reply-fn), `initiate_chat`, and team/`GroupChat` membership. v0.4 adds `handoffs` and `run()`/`run_stream()`. +- **Instantiation:** **Standing and addressable** — the most "agent-like." Instances are stateful (`chat_messages`, `send`/`receive`, `on_messages`, `save_state`/`load_state`, `on_reset`), uniquely named, and referenced by name in multi-agent chats. +- **Closeness to our model:** Captures (a) identity and the standing/addressable end-state well; weak on (b)/(c) — no declared owned/known *files*, only message state. +- **Worth borrowing:** The **two-field identity** — separate the model-facing self-description from the **externally-advertised `description` used for routing/selection.** Maps directly onto "loaded transiently … becomes addressable to gate work": the `description` is what a coordinator reads to decide whether to stand the persona up. + +--- + +## LangGraph — nodes + typed `State` + +- **Definition format:** Graph-centric. `StateGraph(StateSchema)` with nodes added via `add_node(name, fn)`; nodes are plain functions `(state, config) -> partial-state-update`. State is a `TypedDict`/dataclass/Pydantic schema. +- **Portable identity:** **No, at the core layer.** Docs are explicit: "Nodes: Functions that encode the logic of your agents" — there is no agent/role identity object; `StateGraph` is parameterized by *state schema only*. Identity exists only as a named function inside one graph. **The prebuilt layer adds it:** `create_react_agent(model, tools, prompt=..., name=...)` (now deprecated → `langchain.agents.create_agent` with middleware) produces a reusable, named, portable agent that can itself be embedded as a node/subgraph in a larger graph. So portability is opt-in via the prebuilt factory, absent in raw LangGraph. +- **Owned/managed files:** **No file ownership; field-level *state* ownership instead.** This is LangGraph's distinctive contribution: each State key declares a **reducer** via `Annotated[type, reducer]` (e.g. `add_messages`) governing how concurrent writes merge (default = overwrite/last-write-wins). Ownership is by merge-rule, not by file path. +- **Known/context files:** No declared file inputs. Nodes implicitly read the shared `State`; docs note nodes "do not declare which keys they read or write" — read/write sets are implicit. **Subgraphs** can keep **private channels** outside the parent I/O schema (a "knows internally vs exposes" boundary), with a streaming-leak caveat. +- **Processes:** The graph *is* the process — edges/`Command(goto=...)`/conditional routing are first-class; the workflow is the primary artifact, agents secondary. +- **Instantiation:** Nodes are named and addressable as graph members (`add_edge("a","b")`) but execution is transient per super-step; no standing service. Persistence is the *graph's* checkpointer, not a per-agent identity. +- **Closeness to our model:** Furthest from a persona model at its core (workflow-first, identity-thin), yet it uniquely formalizes **artifact ownership semantics** that your *owns* clause leaves implicit. +- **Worth borrowing:** **Reducers as ownership contracts** — when two personas touch the same owned artifact, a declared merge function (append / last-write / custom) resolves contention deterministically. Also the **subgraph private-channel** pattern for *knows*-internal vs externally-visible context. + +--- + +## Cross-cutting takeaways for your model + +1. **Identity-vs-output split is validated prior art, not a quirk:** CrewAI puts identity on `Agent` and outputs on `Task` — independent confirmation of your (a) portable-identity / (b) owns separation. Borrow it: keep the persona's *owns* as references resolved per deployment, not baked into identity. +2. **Two-tier identity for the transient→addressable transition:** AutoGen's `system_message` (self) + `description` (advertised, routing-facing) is the cleanest match to "transiently loaded, becomes addressable to gate work." A coordinator reads the `description`-equivalent to decide when to stand the persona up. +3. **No surveyed system declares *known/context input files* on the role** the way your *knows* clause does — closest is CrewAI's `knowledge_sources` (agent-level) and Task `context` (task-level). This is a genuine gap your model fills; it's a differentiator, not a missing-homework item. +4. **Ownership semantics are under-specified everywhere except LangGraph.** If personas can co-write artifacts, adopt LangGraph-style per-artifact reducers to make *owns* contention deterministic. diff --git a/specs/tk-oe8o0/research/survey-4-roo-cline-cursor-aider.md b/specs/tk-oe8o0/research/survey-4-roo-cline-cursor-aider.md new file mode 100644 index 0000000..a256e02 --- /dev/null +++ b/specs/tk-oe8o0/research/survey-4-roo-cline-cursor-aider.md @@ -0,0 +1,92 @@ +--- +name: Prior-art survey 4 — Roo Code, Cline, Cursor & Aider +description: Full primary-source survey — Roo Code custom modes' fileRegex edit-fence, Cline rules, Cursor's four-mode rule activation taxonomy (always / glob-auto / description-requested / manual), and Aider's read-only vs editable file split. Persisted from the mechanik-thread design session (2026-06-13); indexed by prior-art.md. +--- + +# Persona-System Prior Art Survey + +**Model recap:** persona = (a) portable identity, (b) *owns* (artifacts written AND/OR an edit-restriction), (c) *knows* (read context), (d) *processes* (methods); normally transient, occasionally a standing/addressable agent. + +## Provenance + +| System | Mechanism/artifact | Source (URL + repo/path) | Surveyed at | +|---|---|---|---| +| Roo Code custom modes | Custom mode def: `slug`/`name`/`roleDefinition`/`groups`+`fileRegex`; `.roomodes` / global `custom_modes.yaml` | https://docs.roocode.com/features/custom-modes (→ roocodeinc.github.io/Roo-Code/features/custom-modes); repo `RooCodeInc/Roo-Code`, `RooCodeInc/Roo-Code-Docs/.roomodes` | 2026-06-13 | +| Cline rules | `.clinerules` file or `.clinerules/` dir of `.md`/`.txt`; global `~/Documents/Cline/Rules`; YAML `paths:` frontmatter | https://docs.cline.bot/customization/cline-rules; repo `cline/cline`, community `cline/clinerules` | 2026-06-13 | +| Cursor rules | `.cursor/rules/*.mdc` (frontmatter: `description`/`globs`/`alwaysApply`); legacy `.cursorrules`; User vs Project rules | https://docs.cursor.com/en/context/rules (→ cursor.com/docs); forum.cursor.com/t/.../104879 | 2026-06-13 | +| Aider | `CONVENTIONS.md` + read-only/editable file split (`/read-only`, `--read`, `/add`); `.aider.conf.yml` `read:` | https://aider.chat/docs/usage/conventions.html; https://aider.chat/docs/config/options.html; repo `Aider-AI/aider` | 2026-06-13 | + +> Honesty note: all four primary docs sites issue host redirects (Roo→GitHub Pages, Cursor→`cursor.com/docs`); I followed each and the field-level detail below is from the redirected primary pages, cross-checked against community sources. The Cursor "Manual" type is also rendered "ManualOnly" in one doc surface — same concept. + +--- + +## 1. Roo Code — custom modes (closest analogue; the only one with true edit-restriction) + +- **Definition format.** YAML or JSON object. Project modes in workspace-root `.roomodes`; global modes in `settings/custom_modes.yaml` (or `.json`). Top-level props: `slug` (`^[a-zA-Z0-9-]+$`), `name`, `description`, `roleDefinition`, `whenToUse` (opt), `customInstructions` (opt), `groups`. +- **Portable identity.** Yes, explicitly. `roleDefinition` is the persona ("personality and expertise"); a mode defined in global `custom_modes.yaml` travels across all projects, and a same-`slug` project `.roomodes` mode **completely overrides** the global one (all global props ignored). This is exactly your portable-identity-with-per-deployment-override split. +- **Owned/managed files — RESTRICTS edits (the headline match).** The `edit` entry in `groups` becomes a two-element array carrying a `fileRegex` + optional `description`: + ```yaml + groups: + - read + - - edit + - fileRegex: \.(js|ts)$ + description: JS/TS files only + ``` + (JSON: `["edit", { "fileRegex": "\\.(js|ts)$", "description": "..." }]`.) A blocked write raises a `FileRestrictionError` naming the mode, allowed pattern, description, attempted path, and tool. This is a *negative* ownership (a fence on which files may be edited), not a positive "declares artifacts it writes" manifest — maps to the second half of your "owns" ("a restriction on which files it may edit"). +- **Known/context files.** No declarative read-glob. Read access is a coarse capability (`read` in `groups`); there is no per-mode "these are my inputs" list. Weaker than your *knows*. +- **Processes.** `customInstructions` / `roleDefinition` carry method as prose; modes also compose with Roo's orchestration (e.g. Boomerang/sub-task handoff between modes). No formal workflow binding in the schema. +- **Instantiation.** Transient-by-default and **switchable/addressable**: one active mode at a time, user- or AI-switched (`whenToUse` drives automated selection). Not a standing daemon, but the named, switchable profile is the strongest "becomes addressable" parallel here. +- **Closeness:** Very high — the only surveyed system that unifies portable role + per-project override + hard edit-restriction by regex. +- **Worth borrowing:** The `fileRegex`-on-`edit` shape and the `FileRestrictionError` surface — a ready blueprint for your "owns" fence (and consider a positive write-manifest as the complement Roo lacks). + +## 2. Cline — rules / `.clinerules` + +- **Definition format.** Plain Markdown/text. Single `.clinerules` file *or* a `.clinerules/` directory whose `.md`/`.txt` files are concatenated into the system prompt. Optional numeric prefixes for ordering. Global rules in `~/Documents/Cline/Rules`; workspace rules take precedence on conflict. Also ingests Cursor/Windsurf rules and `AGENTS.md`. +- **Portable identity.** Partial. Global-vs-workspace split gives portability of *instructions*, but there is **no named role/persona object** — rules are ambient guidance, not an identity you instantiate or switch to. (Cline's separate Plan/Act distinction is a workflow phase, not a persona.) +- **Owned/managed files.** None. Docs show **no file-edit-restriction mechanism** within rules; rules cannot fence editable files. No write-manifest either. +- **Known/context files.** Conditional activation via YAML frontmatter `paths:` globs (e.g. `src/components/**`, `*.test.ts`) — a rule loads only when context files match. This is *input-gated activation* (closest to your *knows*), but it scopes *when the rule applies*, not *what the persona reads*. +- **Processes.** Method-as-prose in the rule body; toggleable on/off via the Rules panel (the "self-improving"/AI-editable angle). No structured workflow binding. +- **Instantiation.** Fully transient/ambient — text appended to the prompt; nothing standing or addressable. +- **Closeness:** Low–moderate — portable-vs-project and glob-gated activation only; no identity, no ownership. +- **Worth borrowing:** The runtime **toggle UI** for rules and AGENTS.md interop; the `paths:` glob is a lightweight precedent for declaring context relevance. + +## 3. Cursor — rules (`.cursor/rules/*.mdc`) + +- **Definition format.** `.mdc` = YAML frontmatter (`description`, `globs`, `alwaysApply`) + Markdown body, one file per rule under `.cursor/rules/` (nestable). Plain `.md` w/o frontmatter is ignored for conditional loading. Legacy: single-file `.cursorrules` (deprecated, still read). +- **Portable identity.** Partial. **User Rules** = global (across projects, Chat-only); **Project Rules** = per-repo. Like Cline, this is portable *instruction*, not a named/switchable persona object. +- **Owned/managed files — context only.** Primary doc states plainly: **"Rules provide context only — they do not restrict file editing."** No ownership/fence. The `globs` field looks ownership-like but only controls *auto-attachment of the rule*, not write permission. +- **Known/context files.** Strongest declarative *knows* of the four, via four activation types keyed on frontmatter: + - **Always** (`alwaysApply: true`) — every request; + - **Auto Attached** (`globs` set) — loads when a matching file is in context; + - **Agent Requested** (`description` set, `alwaysApply: false`) — model decides from the description; + - **Manual** (neither) — only via `@rule-name`. +- **Processes.** Method-as-prose in the body; no workflow binding. +- **Instantiation.** Transient/ambient; `@rule-name` makes a rule *referenceable* but not an agent. No standing/addressable persona. +- **Closeness:** Moderate on *knows* (rich glob/description/always taxonomy) and portable-vs-project; **zero on *owns*** by explicit design. +- **Worth borrowing:** The four-mode activation taxonomy (always / glob-auto / description-requested / manual) is the cleanest vocabulary for your *knows* loading semantics — adopt the naming directly. + +## 4. Aider — `CONVENTIONS.md` + read-only/editable split + +- **Definition format.** Convention = ordinary Markdown (`CONVENTIONS.md`, name conventional, not magic). Loaded via `/read-only CONVENTIONS.md`, `aider --read CONVENTIONS.md`, or `.aider.conf.yml` `read: [CONVENTIONS.md, ...]`. Verbatim recommendation: *"It's best to load the conventions file with `/read CONVENTIONS.md` or `aider --read CONVENTIONS.md`"* (so it's read-only + prompt-cached). +- **Portable identity.** Weak. A conventions file is portable project context, but there is **no role/persona/mode** at all — Aider has no named agent identity construct. +- **Owned/managed files — an inverted, per-session ownership.** Aider's core distinction is the one place your *owns* and *knows* both appear, as a runtime split of the chat file set: + - **Editable** files (`/add`) — the model may write them; + - **Read-only** files (`/read-only`, `--read`) — referenced, never edited. + This is effectively a *positive editable-set* (the inverse of Roo's negative regex fence): ownership is "which files I'm allowed to edit this session," chosen per session rather than declared on a persona. No glob/regex; it's an explicit file list. (Note an open request, `Aider-AI/aider#3425`, to separate read-only vs editable via `.aiderignore` — i.e. this is list-based, not pattern-based, today.) +- **Known/context files.** The read-only set *is* the declared read context; `.aider.conf.yml read:` makes it project-persistent. Matches your *knows* well, by explicit path. +- **Processes.** Conventions body carries method-as-prose; Aider's own architect/code modes are workflow phases, not personas. +- **Instantiation.** Per-session, transient; nothing standing/addressable. +- **Closeness:** Moderate on *owns*/*knows* (clean editable-vs-readable split, persistable), but no identity and no patterns. +- **Worth borrowing:** The **editable-set ⊕ read-only-set** framing — pairs naturally with Roo's regex fence: your "owns" could express *both* a positive write-manifest (Aider-style) and a negative edit-fence (Roo-style), and Aider shows read-only context should be **prompt-cached**. + +--- + +## Synthesis for your model + +- **Owns (edit-restriction):** Only **Roo Code** enforces it — regex fence on the `edit` capability with a typed `FileRestrictionError`. **Aider** offers the positive complement (per-session editable set). **Cursor explicitly does not restrict edits; Cline has no such mechanism.** Borrow Roo's regex-fence shape + Aider's positive editable-set; your "owns" can carry both a write-manifest and an edit-fence, which no single system does. +- **Knows (read context):** **Cursor's** four-type activation (always / glob-auto / description-requested / manual) is the richest declarative vocabulary; **Cline's** `paths:` and **Aider's** read-only set are simpler precedents. Borrow Cursor's taxonomy naming. +- **Portable identity + per-deployment override:** **Roo** is the only true match (global mode ⇄ project `.roomodes` override by `slug`); Cline/Cursor only split global-vs-project *instructions* with no identity object. +- **Instantiation (standing/addressable):** None run a persona as a standing daemon; **Roo's** switchable named modes (and Cursor's `@rule-name` reference) are the nearest "becomes addressable" precedents — your transient-load-then-promote-to-standing-agent design appears to be **net-new** relative to all four. +- **Processes:** Uniformly weak — all four encode method as prose in a role/rules body; none bind a persona to a structured workflow. This is open design space. + +**Sources:** [Roo custom modes](https://docs.roocode.com/features/custom-modes) · [Roo-Code-Docs `.roomodes`](https://github.com/RooCodeInc/Roo-Code-Docs/blob/main/.roomodes) · [Cline rules](https://docs.cline.bot/customization/cline-rules) · [cline/clinerules](https://github.com/cline/clinerules) · [Cursor rules](https://docs.cursor.com/en/context/rules) · [Cursor MDC forum](https://forum.cursor.com/t/cursor-rules-mdc-clarification/104879) · [Aider conventions](https://aider.chat/docs/usage/conventions.html) · [Aider options](https://aider.chat/docs/config/options.html) · [aider#3425 read-only vs editable](https://github.com/Aider-AI/aider/issues/3425) diff --git a/specs/tk-oe8o0/research/survey-5-claude-kiro-amazonq.md b/specs/tk-oe8o0/research/survey-5-claude-kiro-amazonq.md new file mode 100644 index 0000000..30e503d --- /dev/null +++ b/specs/tk-oe8o0/research/survey-5-claude-kiro-amazonq.md @@ -0,0 +1,87 @@ +--- +name: Prior-art survey 5 — Claude Code, Kiro & Amazon Q +description: Full primary-source survey — Claude Code subagents + skills (scope ladder, progressive disclosure), Kiro steering inclusion modes (always / fileMatch / manual), and Amazon Q custom agents' resources globs + toolsSettings path scoping. Persisted from the mechanik-thread design session (2026-06-13); indexed by prior-art.md. +--- + +# Persona-system prior-art survey + +## Provenance + +| System | Mechanism / artifact | Source (URL + repo/path) | Surveyed at | +|---|---|---|---| +| Claude Code subagents | `.claude/agents/*.md` (+ `~/.claude/agents/`, plugin `agents/`) — YAML frontmatter + Markdown system prompt | https://code.claude.com/docs/en/sub-agents | 2026-06-13 | +| Claude Code Skills | `/SKILL.md` (+ bundled dir) — YAML frontmatter + body; Agent Skills open standard (agentskills.io) | https://code.claude.com/docs/en/skills ; https://platform.claude.com/docs/en/agents-and-tools/agent-skills/overview | 2026-06-13 | +| Kiro steering | `.kiro/steering/*.md` (+ `~/.kiro/steering/`) — YAML frontmatter `inclusion` modes | https://kiro.dev/docs/steering/ | 2026-06-13 | +| Kiro specs | `.kiro/specs/{feature}/{requirements,design,tasks}.md` | https://kiro.dev/docs/specs/ | 2026-06-13 | +| Amazon Q Developer (CLI custom agents) | `.amazonq/cli-agents/*.json` — JSON schema | https://docs.aws.amazon.com/amazonq/latest/qdeveloper-ug/command-line-custom-agents-configuration.html ; verbatim config in https://github.com/aws/amazon-q-developer-cli/issues/2510 | 2026-06-13 | + +Honesty notes: the AWS `docs.aws.amazon.com` pages are a JS-rendered SPA that returned only a title to WebFetch — the Amazon Q schema below is verified from (a) a verbatim user config in aws/amazon-q-developer-cli issue #2510 and (b) the AWS-docs search snippet, not from my own read of the rendered config-reference page. Kiro's `inclusion: auto` mode (with `name`/`description`) appeared in one community-sourced format spec but is **not** in the official kiro.dev steering page (which documents only `always`/`fileMatch`/`manual`); treat `auto` as unverified. + +--- + +## 1. Claude Code subagents + +- **Definition format:** One Markdown file per agent with YAML frontmatter; the Markdown body **is** the system prompt. Loaded at session start. Also definable transiently via `--agents ''` (same field set, `prompt` key replaces the body). +- **Portable identity:** Yes, strongly. The frontmatter `name` + `description` + body prompt are a self-contained role. Scope ladder: managed (org) > `--agents` (session) > `.claude/agents/` (project) > `~/.claude/agents/` (all your projects) > plugin `agents/` (lowest). User-scope and plugin distribution are the explicit portability paths ("Reuse configurations across projects"). Identity comes **only** from the `name` field, not the path. +- **Owned/managed files:** Not as a declared artifact list. The closest analog is `memory: user|project|local`, which grants a persistent dir (`~/.claude/agent-memory//`, etc.) the agent reads/curates across sessions (auto-injects first 200 lines of its `MEMORY.md`). That's owned *state*, not declared *outputs*. +- **Known/context files:** No glob/fileMatch inclusion. A non-fork subagent starts with a **fresh, isolated** context (system prompt + delegation message + CLAUDE.md hierarchy + git snapshot); it does not declare input file patterns. `skills:` can preload whole skills into context. Context-scoping is by isolation, not by declared globs. +- **Processes:** Bound via the prompt body plus `hooks` (`PreToolUse`/`PostToolUse`/`Stop`→`SubagentStop`) for lifecycle validation, and `skills:` for preloaded methods. No first-class "workflow" object. +- **Instantiation:** Transient by default — spawned per task via the Agent tool, runs in its own context window, returns only a summary. Tool grants: `tools` (allowlist) / `disallowedTools` (denylist), `Agent(type,…)` to gate which sub-subagents it may spawn, plus `permissionMode`, `model`, `maxTurns`, `mcpServers`, `effort`, `isolation: worktree`, `background`. **Addressable:** yes — `@agent-` / `@"name (agent)"`, natural-language naming, or session-wide via `--agent ` (the agent's prompt replaces the default system prompt). Resumable by agent ID. It becomes "standing" only as a background task or via `--agent`. +- **Closeness:** Very close to the *standing/addressable-agent* end of your model (gate-work + patrol), with portable identity — but weak on declared owns/knows. +- **Worth borrowing:** The scope-precedence ladder (managed > session > project > user > plugin) and `Agent(type,…)` spawn-gating are a clean, ready-made model for "portable identity + who-can-invoke-whom." + +## 2. Claude Code Skills + +- **Definition format:** A directory with `SKILL.md` (YAML frontmatter + Markdown body) as the entrypoint, optionally bundling `scripts/`, `references/`, `assets/`, templates. Follows the **Agent Skills open standard** (cross-tool). Only `name`/`description` are meaningful-required (Claude Code makes both optional, defaulting `name` to the dir). +- **Portable identity:** Yes — this is the system's whole point ("create once, use automatically," "package domain expertise"). Same scope ladder as subagents (enterprise > personal `~/.claude/skills/` > project `.claude/skills/` > plugin). API/claude.ai variants package as zip/`skill_id`. Caveat: skills **do not sync across surfaces** (Code/API/claude.ai managed separately). +- **Owned/managed files:** Bundles owned artifacts (scripts/templates/references) that travel **with** the persona — the strongest "owns its artifacts" story here — but these are inputs/tools it carries, not project-relative outputs it maintains. No declared write-targets. +- **Known/context files:** No glob/fileMatch *auto-inclusion*. Instead: **progressive disclosure** — L1 metadata (name+description, always in prompt, ~100 tok) → L2 `SKILL.md` body on trigger → L3 bundled files read on demand via bash. Plus **dynamic context injection**: `` !`` `` lines run and inline output before Claude sees the body (e.g. `!​`git diff HEAD``). Context is pulled by reference/command, not matched by file glob. +- **Processes:** This is the core — a skill *is* a packaged method/workflow (`context: fork` runs it in a subagent; `disable-model-invocation: true` makes it a deliberate `/command`). +- **Instantiation:** Transient and **non-addressable as an agent** — runs inline in the main conversation context (or a forked subagent). Tool grant: `allowed-tools: Read Grep` (space-separated; note the hyphenated spelling, distinct from subagents' comma `tools:`). Invoked by Claude automatically or by the user as `/skill-name`. Never "stands up" as an agent. +- **Closeness:** Closest to your *processes* + *portable identity* facets, and to the "loaded transiently" default — but deliberately the opposite of "standing/addressable." +- **Worth borrowing:** Progressive disclosure (3-level lazy load keyed off a cheap always-on description) + `!`cmd`` dynamic injection — directly model your *knows* facet as **pulled-on-demand** rather than glob-included, which scales context far better. + +## 3. Kiro steering files + +- **Definition format:** `.kiro/steering/*.md`, YAML frontmatter (triple-dash) carrying an `inclusion` mode. Three default foundational files: `product.md`, `tech.md`, `structure.md`. +- **Portable identity:** Weak. Files are workspace-specific (`.kiro/steering/`) or machine-global (`~/.kiro/steering/`); docs explicitly say they're "not inherently portable across projects." (And a known bug — issue #6171 — that global `~/.kiro/steering/` files don't inject regardless of mode.) These are *standards/context*, not an addressable role. +- **Owned/managed files:** None declared. Steering is read-only guidance Claude *consumes*; it doesn't declare artifacts it writes. +- **Known/context files:** **This is the standout match for your *knows* facet.** `inclusion` modes: + - `always` (default) — loaded into every interaction; + - `fileMatch` + `fileMatchPattern: ""` (single or array, e.g. `["**/*.ts","**/*.tsx"]`, `"app/api/**/*"`) — auto-included **only** when the active file matches the glob; + - `manual` — pulled on demand via `#steering-file-name` in chat. + + This is exactly declared, glob-scoped context inclusion. (Reported flaky for extension-only patterns — issue #1643.) +- **Processes:** Not in steering itself. The **spec workflow** (separate, `.kiro/specs/{feature}/`) is the process layer: `requirements.md` → `design.md` → `tasks.md`, a 3-phase requirements→design→tasks→implementation flow, with tasks grouped into dependency "waves." Steering supplies durable standards *to* that workflow. +- **Instantiation:** Not an agent at all — purely context/guidance documents; transient per-interaction, never standing or addressable. No tool grants. +- **Closeness:** The purest expression of your *knows* (project-relative, glob-scoped, conditional) — and `manual`/`#ref` mirrors your "transient until summoned." But it has no identity/owns/agent facets. +- **Worth borrowing:** Adopt `inclusion: {always | fileMatch + fileMatchPattern | manual}` near-verbatim for your *knows* declaration — it's the cleanest existing schema for "read this context only when working on matching files," and the `always`/`fileMatch`/`manual` triad maps onto portable-core vs. project-scoped vs. on-demand context. + +## 4. Amazon Q Developer (CLI custom agents) + +- **Definition format:** One **JSON** file per agent in `.amazonq/cli-agents/` (local) or a global location; precedence local > global > built-in default. Generated via `/agent generate`; run via `q chat --agent `. +- **Portable identity:** Yes — `name` + `description` + `prompt` define a reusable role, with local-vs-global scoping for cross-project reuse. Same two-tier (project/global) portability shape as the Claude systems. +- **Owned/managed files:** Not a declared output set. (`fs_write` capability + `toolsSettings.allowedPaths` bound *where* it may write, but it doesn't enumerate maintained artifacts.) +- **Known/context files:** **Yes, and closest to "declared inputs by glob."** `resources` is an array of `file://` URIs **with glob support**, e.g. (verbatim from issue #2510): + ```json + "resources": ["file://AmazonQ.md", "file://README.md", "file://.amazonq/rules/**/*.md"] + ``` + These are statically loaded into context. Beyond static `resources`, **context `hooks`** inject *dynamic* context (e.g. run `git status` and feed the output in) — combining Kiro's glob-inclusion idea with Skills' command-injection idea in one schema. +- **Processes:** Via `prompt` + `hooks` (dynamic context / lifecycle). No separate workflow object. +- **Instantiation:** Transient per `q chat --agent` session. Tool grants are the richest here: `tools` (e.g. `["*"]`), `allowedTools` (auto-trust allowlist — names like `fs_read`, `execute_bash`, MCP tool names), `toolAliases`, `mcpServers` (inline command/args/env), and **`toolsSettings`** with fine-grained `allowedPaths`/`deniedPaths` (fs tools) and `allowedCommands`/`deniedCommands` (bash). Invoked by name on the CLI; not a continuously-addressable standing agent. +- **Closeness:** The most complete single-artifact match to your model — identity (`prompt`) + knows (`resources` globs + `hooks`) + tool grants in one declaration — just JSON instead of frontmatter+body, and transient-only. +- **Worth borrowing:** Two ideas: (1) `resources: ["file://…/**/*.md"]` as an explicit *static-include* glob list, paired with (2) `toolsSettings` path/command allow-&-deny lists for capability scoping finer than a tool allowlist — together they let one persona declare *knows* and bounded *owns*-write-scope side by side. + +--- + +## Synthesis against your four facets + +| Facet | Best prior art | How it's expressed | +|---|---|---| +| **(a) portable identity** | CC subagents / Skills / Q agents | Reusable `name`+`description`+prompt(body or `prompt`); user/global scope + plugin packaging for cross-project travel. Scope-precedence ladder (managed > session > project > user > plugin) is the reusable pattern. | +| **(b) owns (writes/maintains)** | *Weakest across the board* | No system declares output artifacts. Nearest: CC subagent `memory:` (owned state dir), Skills' bundled `scripts/templates` (owned carried assets), Q `toolsSettings.allowedPaths` (bounded write scope). **Gap to fill yourself.** | +| **(c) knows (declared inputs)** | **Kiro steering** + **Q `resources`** | Kiro `inclusion: fileMatch`/`fileMatchPattern` glob = conditional context; Q `resources: file://…/**/*.md` = static glob include; Skills' progressive disclosure + `!`cmd`` = pulled-on-demand. Three viable models: glob-conditional, static-glob, lazy-pull. | +| **(d) processes** | **Skills** (+ Kiro specs) | A Skill *is* a packaged method; Kiro specs give a requirements→design→tasks workflow with dependency waves; hooks bind lifecycle steps. | +| **transient → standing/addressable** | **CC subagents** | Default transient (spawn-summarize-return); becomes standing via `--agent`/background; addressable via `@agent-` and resumable by ID. The only surveyed system that cleanly spans both. | + +**Bottom line for your design:** No single prior-art system covers all four facets. Subagents own the *identity + transient↔standing/addressable* axis; Skills own *processes + portable-packaging + lazy context*; Kiro steering owns *declared, glob-scoped knows*; Amazon Q is the densest single schema (identity + glob-resources + dynamic hooks + fine-grained tool/path scoping). The unowned territory is **(b) declared owned/maintained artifacts** — every system gives you write *capability* or *scope*, none lets a persona declare the project-relative artifacts it *maintains*. That's the novel slot your model adds, and worth designing deliberately rather than borrowing.