Tasks: show the configured remote agents to the model
The last spec artifact (requirements → design → testing plan → tasks). Derived from the approved
design.mdandtesting-plan.md. Six tasks: four independent building blocks, the runtime wiring that joins them, then the docs.
Task list
Each task is test-first: write the test, watch it fail, then make it pass. Commands run from the repository root.
[x] 1. Agent roster builder (
tiny_harness/harness/agents/roster.py)AgentRoster,clean_field,build_rosterand the caps, as in design § Components. Wrap a non-empty body withrender_untrusted_text(…, "agent-cards").(no agents)when empty. Export fromtiny_harness.harness.agents.- Unit tests in
tests/unit/agents/test_roster.py: ordering, fields, empty roster,skills: (none), each cap and…,(n more), thetruncatedreport, no URL in the output. - Security tests in
tests/security/test_agent_roster.py: abuse cases 1 (injected text only inside the untrusted block), 2 (</agents>,</untrusted>, newlines, control characters → one single-line entry) and 3 (10 kB description, 50 skills → within caps). - Depends on: none
- Requirements: R1.2, R1.3, R1.4, R4.1, abuse cases 1–3
- Test: T1 —
uv run pytest tests/unit/agents/test_roster.py; T8 —uv run pytest tests/security/test_agent_roster.py(red→green)
[x] 2.
agentssection in the context window (core/context.py,core/inprocess.py)ORDERgainsagentsafterparticipants.NEVER_COMPACTgainsagents.ContextWindowManager.assemble(agents_roster=…)adds theSTATICsection.InProcessOperations(agents_roster=…)stores it and passes it through.- Unit tests in
tests/unit/core/: the section isSTATIC, never compacted, afterparticipants, defaults to(no agents), andinstructions()is byte-identical across two turns. - Depends on: none
- Requirements: R1.1, R1.4, R1.5, R1.7
- Test: T1 —
uv run pytest tests/unit/core -k agents(red→green)
[x] 3.
spawn_subtaskrefuses an unknown agent (core/intrinsics.py,core/inprocess.py,tools/intrinsics.py)core_intrinsics(context, *, known_agents=…). Inbind(), pass a callable that readsregistry.list(EntityKind.AGENT). Unknown or emptyagentreturnsToolResult.error(…, "agent.unknown", …)listing the valid ids, with no command.- New
SpawnSubtaskArgs.agentdescription. Regeneratedocs/a2a/ext/intrinsics/spawn_subtask.jsonwithUPDATE_API_SNAPSHOTS=1. - Unit tests: unknown, empty, known and null
agent. Security test (abuse case 4):agent="https://evil.example"→agent.unknown, no command, no HTTP request. - Depends on: none
- Requirements: R2.2, R3.1, R3.2, R3.3, abuse case 4
- Test: T1 —
uv run pytest tests/unit/core -k spawn; T3 —uv run pytest tests/contract/test_intrinsic_schemas.py; T8 —uv run pytest tests/security/test_agent_roster.py -k unknown(red→green)
[x] 4. System prompt
## agentssection (systemprompt.md,prompts/entity.py)- Add the section text from design § System prompt between
skillsandrules.SECTION_ORDERgainsagentsin the same place. - Unit tests in
tests/unit/prompts/: the section exists and states each R2.1 point. A prompt withextends: agentsappends to it. - Depends on: none
- Requirements: R2.1, R2.3
- Test: T1 —
uv run pytest tests/unit/prompts; T3 —uv run pytest tests/contract/test_prompts_api.py(red→green)
- Add the section text from design § System prompt between
[x] 5. Wire the roster into
build_runtime(service/runtime.py)- After the agents are registered: build the roster, log
INFOwith the ids, log oneWARNINGper truncation, and passroster.texttoInProcessOperations. - Integration tests in
tests/integration/agents/test_agents_roster.py, each with a Gherkin docstring and aRequirement:link, for the five T2 scenarios and the T8 hostile-card scenario intesting-plan.md. Use a fake A2A agent andFakeLLM. - Update the public-API snapshots (
tests/contract/snapshots/) for the new names, on purpose, and check nothing else changed. - Depends on: 1, 2, 3, 4
- Requirements: R1.1, R1.6, R3.1, R3.2, R4.2, NFR both engines, NFR observability
- Test: T2 —
uv run pytest tests/integration/agents/test_agents_roster.py; T3 —uv run pytest tests/contract(red→green)
- After the agents are registered: build the roster, log
[x] 6. Documentation
- Capability docs:
remote-agents.md(the roster, the unknown-id refusal),context-window.md(theagentssection),prompts-and-skills.md(theagentsprompt section), each with an issue-34 history row. - User docs, following
.agents/skills/docs-writing/SKILL.md:docs/configuration/plugins-and-agents.md, which explains what the model sees for each configured agent and why a good card description matters. - Record both in
docs/specs/issue-34/evidence/documentation.md. - Depends on: 5
- Requirements: NFR docs
- Test:
uv run pre-commit run --all-files(markdownlint) andcd docs && bun run docs:build(no dead links)
- Capability docs:
[x] 7.
[card]configures this agent's own card (config.py,service/a2a/card.py,service/process.py)- Added after approval, from PR review (R5).
CardConfig,CardSkillConfig,Settings.card;describe();servebuilds the card fromdescribe(settings.card). - Unit tests in
tests/unit/test_config_card.py; the scenario "A tiny-harness described by its card section is listed by another"; the settings schema and config API snapshots regenerated on purpose. - Docs:
[card]indocs/configuration/plugins-and-agents.md, theconfigurationanda2a-servercapability docs. - Depends on: 5
- Requirements: R5.1–R5.4
- Test: T12 (red→green)
- Added after approval, from PR review (R5).
[x] 8. The delegation example (
examples/delegation/,docs/sdk/example-delegation.md)- Added after approval, from PR review (R6). The ledger and front-desk configurations, the ledger's read-only plugin, the README, the guide and its sidebar entry.
- Depends on: 7
- Requirements: R6.1–R6.3
- Test: T12 (the example configs load and pair up); T13 (run with a real model)
[x] 9.
selfandspawn_subtaskon the A2A route (R7.1–R7.7)- Added after approval, from PR review.
selfregistered;start_agent_taskandcancel_remote_task; the parent creates everyspawn_subtaskchild over A2A and starts the stand-in on it; the trust rule ([server] delegators); the follow skips replayed history; streams are closed; completion waits for an unread result. - Tests:
test_self_delegation.py; the remote tests and the three durable tests that spawn a child, on the streaming transport andself_hosted. - Depends on: 8
- Requirements: R7.1–R7.7, abuse cases 5–7
- Added after approval, from PR review.
[x] 10.
/sub-taskandcreate_task_for_participanton the A2A route (R7.2)- The brief for a conversation child (no text; the person as reporter) and for a participant task (the person as assignee, a
participant-mode workflow); the direct_start_local_childpath removed. - Depends on: 9
- Requirements: R7.2, R7.4
- The brief for a conversation child (no text; the person as reporter) and for a participant task (the person as assignee, a
[x] 11. Docs, evidence and a real-model run for R7
- Depends on: 10
Dependency graph (DAG)
Tasks 1–4 touch separate files and can run in any order.
Checkpoints
- After each task: its own tests, then
uv run pre-commit run --all-files(ruff, pyright, unit tests, markdownlint), then a commit that names the task and its red→green. - After task 5:
uv run pytest tests/integration tests/contract tests/security tests/ui, the CI set. - After task 6: the docs build.
- Then the
verificationnode runstesting-plan.md(including the manual T11). The review phases follow: self and critic rounds and the security review gate, recorded inevidence/.
Review comments
Appended by the-loop's
record-feedbackhook when a human gate approves with comments (issue-109). Append-only and attributed: an approval never silently discards a reviewer's suggestions, and the feedback travels with the document it concerns rather than living in a side-channel tracker.