Tasks: tiny-harness: A tiny agent harness
The last spec artifact (requirements → design → testing plan → tasks). A DAG of implementation tasks derived from the approved design and testing plan. MUST be reviewed/approved before implementation begins. Once approved, the-loop executes these end-to-end with minimal/no intervention.
The work is cut into the nine stacked pull-request layers of design.md § Stacked pull requests (the approver's Q1 answer: one work item, stacked PRs). Each layer is one PR against the previous layer's branch, merged in order; the tasks inside a layer are the DAG nodes. Every task names the requirement it satisfies, the testing-plan row that proves it and the test that goes red first. The design's two open questions were answered by the approval with no comment, so their defaults stand: Requirement 22.4 is read as "official A2UI renderer, no agent-side A2UI SDK", and the crash demo's guarantee is proved at its two kill points.
Conventions for every task: pyright strict with zero errors and no Any (T13); the public interface it introduces is pinned by a contract test in tests/contract/ (T3) in the same task; integration tests carry the Gherkin docstring with Requirement: docs/specs/issue-3/requirements.md#R<n> (T2); the commit message records the test command and its red→green transition.
Task list
Each task is a checkbox, references the requirement(s) it satisfies, declares its dependencies so the-loop can build the execution DAG, and names the test(s) that will prove it — a row of testing-plan.md's matrix, so the DAG and the plan cannot describe different work. Keep tasks small and verifiable. TDD invariant: no production code without a failing test that motivates it — write/adjust the test first, watch it go red, then make it green. Security-relevant tasks (they touch a trust boundary from design.md §Security design) name the negative test proving the boundary holds — abuse cases are tests like any other (reference/security.md).
Layer 1 — entities, hooks, configuration, errors (branch loop/issue-3-l1-entities)
- [x] 1. Package layout and dependency baseline
- Create the module tree of
design.md§ Layers and modules (interaction/,service/,harness/,config.py,errors.py,builtin/), each with a docstring; add the Layer-1 dependencies topyproject.toml(pydantic,pydantic-settings,packaging,pyyamlpromoted to runtime,jsonschema) and the test folderstests/{unit,integration,contract,security,ui,e2e}with markers (e2eskipped withoutOPENAI_API_KEY/TEMPORAL_API_KEY); add the CIAnygrep gate to.pre-commit-config.yaml(grep -rnE '\bAny\b' tiny_harnessfails the hook). Remove thehello_worldexample and its tests. - Depends on: none
- Requirements: R22.1, R22.2, R22.5
- Test: T13 —
uv run pre-commit run --all-filesgreen;tests/unit/test_layout.py::test_modules_mirror_diagram(red→green)
- Create the module tree of
- [x] 2. Error hierarchy
errors.py:TinyHarnessErrorand every subclass ofdesign.md§ Error handling, each with acodeand amodel_dump-able detail that never carries a secret.- Depends on: 1
- Requirements: R22.3
- Test: T1 —
tests/unit/test_errors.py(codes unique, no secret field); T3 —tests/contract/test_errors_api.py
- [x] 3. Entity base,
EntityRef,TransportProtocol,RemoteLocationharness/entities/base.pyper the design;version: str | None; a remote location requires a protocol.- Depends on: 2
- Requirements: R1.1, R1.2, R1.4, R1.5
- Test: T1 —
tests/unit/entities/test_ref.py(version None allowed, remote without protocol refused); T3 — API snapshot
- [x] 4. Registry with PEP 440 resolution
harness/entities/registry.py:add/get/remove/list, instance | factory | remote entries, sherma'sfind_best_matchonpackaging.SpecifierSet,*= latest concrete,EntityNotFoundError/VersionNotFoundError/RegistryConflictError.- Depends on: 3
- Requirements: R1.2, R1.3, R1.6, R1.7
- Test: T1 —
tests/unit/entities/test_registry.py(resolution matrix from sherma's tests, conflict refused, override order); T3
- [x] 5. Hook points, contexts and
HookManagerharness/hooks/:Operation,Phase,HookPoint,HookContextand the full context catalogue of the design,HookAbort,HookExecutorprotocol withpriority,HookManager.runchain semantics (Nonepasses through, returned context replaces, priority then registration order,indefault at 1000).- Depends on: 4
- Requirements: R2.1–R2.5, R2.9, R2.10
- Test: T1 —
tests/unit/hooks/test_manager.py(order, replacement, abort, single-call veto); T3 —tests/contract/test_hook_contexts_schema.py(every context's JSON schema snapshot)
- [x] 6. Remote hook executors (JSON-RPC and MCP)
JsonRpcHookExecutor(url)andMcpHookExecutor(server)ported from sherma with Pydantic serialisation of contexts; a transport error raisesHookTransportError(no pass-through).- Depends on: 5
- Requirements: R2.6
- Test: T1 —
tests/unit/hooks/test_remote.pywith a stub JSON-RPC server and a scripted MCP stdio server;test_unreachable_remote_hook_raises(negative, fail-closed)
- [x] 7. Providers (HTTP client, clock, random)
harness/hooks/providers.py:Providerswithhttp_client_factory,clock,random; a default and a test fake.- Depends on: 5
- Requirements: R2.7
- Test: T1 —
tests/unit/hooks/test_providers.py
- [x] 8. Configuration models
config.py: every model ofdesign.md§ Configuration (Settings,TemporalConfig,OpenAIConfig,AnthropicConfig,ServerConfig,HeartbeatConfig,StoreConfig,O11yConfig,RetryPolicySpec,RetryPolicies,ContextConfig,RetentionConfig,push_key),extra="forbid", secrets asSecretStr, env-driven;.env.examplewith the twosecret-toollookups.- Depends on: 2
- Requirements: R21.1–R21.3
- Test: T1 —
tests/unit/test_config.py(test_missing_secret_names_variable,test_unknown_key_rejected); T3 —SettingsJSON schema snapshot
- [x] 9. Redactor
harness/security/redactor.py: regexes for bearer tokens,sk-/tmprlshapes,Authorizationheaders, configured secret values;scrub(model)for Pydantic models andscrub_text.- Depends on: 8
- Requirements: R17.6, abuse case 6
- Test: T8 —
tests/security/test_redactor.py::test_redactor_masks_tokens
Layer 2 — plugins, prompts, skills, built-in plugin (branch loop/issue-3-l2-plugins)
- [x] 10. Agent Plugins manifest models and loader
harness/plugins/:PluginManifest,McpServerDef,McpHttpServerDef,HookDef,PromptDef,Plugin,PluginLoader.load_directory/load,LoadReport; validation against the published 1.0.0 schemas (vendored underharness/plugins/schemas/), the namespace directoryio.github.madarauchiha-314.tiny-harness/, component-level skip-and-continue.- Depends on: 4, 5, 8
- Requirements: R3.1–R3.5, R3.8
- Test: T2 —
Feature: Plugins,Scenario: a directory plugin registers its skills, MCP tools, hooks and prompts;Scenario: a programmatic plugin registers the same components; T1 — malformed manifest, duplicate(id, version)
- [x] 11. Plugin path and expansion rules (security)
- Path containment for every component and
cwd;${PLUGIN_ROOT}/${PLUGIN_DATA}expansion inargs,envvalues,cwdonly;${incommandis aPluginError. - Depends on: 10
- Requirements: R3.6, R3.7, abuse case 3
- Test: T8 —
test_plugin_path_escape_rejected,test_command_with_expansion_rejected
- Path containment for every component and
- [x] 12. Prompt entity and the default system prompt as markdown
harness/prompts/:PromptEntitywith##-section parsing;builtin/systemprompt.md(role, task, participants, tools, skills, rules); replace-whole-file and extend-section from a plugin.- Depends on: 10
- Requirements: R4.1, R4.2, R4.4
- Test: T1 —
tests/unit/prompts/test_prompt.py; T6 — snapshot of the default sections
- [x] 13. Agent Skills loader
harness/skills/:SkillFrontMatterwith the specification's constraints,Skill,SkillLoader(YAML front matter, body, resources one level deep), skip with reason on invalid front matter.- Depends on: 10
- Requirements: R5.1, R5.2, R5.4, R5.5
- Test: T1 —
tests/unit/skills/test_loader.py(name/description rules, invalid skipped); T3
- [x] 14. Built-in plugin skeleton
builtin/plugin.jsonand namespace dir loaded first by the same loader; registers the default prompt; placeholders for the intrinsics and default bodies filled by later tasks.- Depends on: 10, 12
- Requirements: R3.9
- Test: T2 —
Scenario: the built-in plugin loads first and is overridable by a lower-priority executor
Layer 3 — models and tools (branch loop/issue-3-l3-models-tools)
- [x] 15. LLM interface, request/response models,
FakeLLMharness/models/llm.py:LLMRequest,LLMResponse,Usage,LLMModelInfo,LLMentity withinvoke/stream;FakeLLMscripted for tests.- Depends on: 4
- Requirements: R18.1, R18.6
- Test: T1 —
tests/unit/models/test_llm_interface.py; T3 — API snapshot
- [x] 16. OpenAI adapter (Responses API)
OpenAILLM:AsyncOpenAI(max_retries=0),responses.createwithinstructions= static prefix,inputitems, tools as function tools,prompt_cache_key,store=False,max_output_tokens; parseoutputitems intotool_callsandUsage(includingcached_tokens); structured output viatext.format;RetryableProviderErroron 429/5xx/network.- Depends on: 15, 8
- Requirements: R18.1, R18.3, R18.5, R10.3
- Test: T1 —
tests/unit/models/test_openai.pyon recorded fixtures (tests/fixtures/openai/),test_provider_retries_disabled,test_cached_tokens_parsed
- [x] 17. Anthropic adapter (configurable, not exercised e2e)
AnthropicLLMovermessages.createwithcache_controlon the static prefix, tool use blocks mapped toToolCall.- Depends on: 15
- Requirements: R18.1, R21.4
- Test: T1 —
tests/unit/models/test_anthropic.pyon recorded fixtures
- [x] 18. System One interface and
FakeSystemOneharness/models/system_one.py: question and answer unions mirroringtypesafe-sdk,SystemOne.decide(..., timeout),FakeSystemOne; no Jev client.- Depends on: 4
- Requirements: R18.2
- Test: T1 —
tests/unit/models/test_system_one.py; T3 — API snapshot
- [x] 19. Tool definitions, calls, results, validation
harness/tools/:Idempotency,Execution,ToolDefinition,ToolCall,ToolResult(untrusted),WorkflowCommand,Toolentity;jsonschemaargument validation;ToolNotFoundError/ToolArgumentErroras error results.- Depends on: 4
- Requirements: R6.3, R6.4, R6.5, R6.7
- Test: T8 —
test_unknown_tool_rejected,test_injected_tool_call_not_executed; T1 — argument validation
- [x] 20. MCP tool source
McpToolSourceonmcp.Client(stdio viaStdioServerParameters, streamable HTTP via URL): list tools, mapannotations.idempotent_hint/read_only_hinttoIdempotency, schema hash at registration, re-list per iteration andToolSchemaChangedErroron mismatch,CallToolResult→ToolResult.- Depends on: 19
- Requirements: R6.1, R6.2, R6.6, abuse case 8
- Test: T2 —
Feature: MCP tools,Scenario: a stdio MCP server's tools are registered with their schemas; T8 —test_schema_drift_refuses_invoke
- [x] 21. Intrinsic tool definitions and argument models
- The twelve intrinsics'
ToolDefinitions (execution=INTRINSIC) with Pydantic argument models and generated JSON schemas committed underdocs/a2a/ext/; registered by the built-in plugin; bodies land in Layer 4. - Depends on: 19, 14
- Requirements: decision-004, R23.1
- Test: T3 —
tests/contract/test_intrinsic_schemas.py(schemas match the committed files)
- The twelve intrinsics'
- [x] 22. Skill intrinsics
list_skills,load_skill,unload_skill,list_skill_resources,load_skill_resourcebodies: read the skill, connect itsmcp.jsonservers, register their tools, returnskill_loaded/skill_unloadedcommands.- Depends on: 13, 20, 21
- Requirements: R5.3, R5.6
- Test: T2 —
Scenario: a loaded skill's MCP tools appear and disappear with load and unload
Layer 4 — core loop, context, persistence (branch loop/issue-3-l4-core)
- [x] 23. Task extension,
HarnessTask, participants, plan and stepsharness/core/:Role,Participant,TaskRef,AcceptanceCriterion,TaskExtensionData,TASK_EXT_KEY,HarnessTaskview overa2a.types.Task(ProtoJsonhelper,participant_of),Step,Planwith the acyclic validator; extension JSON schema committed underdocs/a2a/ext/task.json.- Depends on: 4, 2
- Requirements: R8.1, R8.2, R8.3, R9.1, R9.5
- Test: T1 —
tests/unit/core/test_task.py(metadata round trip),test_plan.py(cycle rejected); T3 —tests/contract/test_task_extension_schema.py
- [x] 24. Agent state and schema-validated subsets
AgentState(history, summary, loaded skills,data: SchemaValidated), plugin schema registration, validated writes.- Depends on: 23
- Requirements: R10.1
- Test: T1 —
tests/unit/core/test_state.py(invalid write rejected)
- [x] 25. Context window manager
ContextWindowManager.assemblewith the stability-ordered sections, tool definitions in the static prefix, untrusted-block rendering of tool results, token estimation from the previous usage plus the 4-chars estimate.- Depends on: 24, 12, 19
- Requirements: R4.3, R10.2, R10.3, R6.5
- Test: T1 —
tests/unit/core/test_context.py(order by stability, static prefix byte-identical across turns, untrusted preamble present)
- [x] 26. Compaction with three
inpoliciescompaction.trigger.in,compaction.keep.in,compaction.summarise.indefaults in the built-in plugin; never-compact set;CompactionRecord.- Depends on: 25, 15
- Requirements: R10.4–R10.8
- Test: T1 —
tests/unit/core/test_compaction.py(keep set intact, record written, policies replaceable)
- [x] 27. Persistence store interface and
SqliteStoreharness/persistence/:Storeentity, everyRecordkind includingPushConfigRecordwith AES-GCM-encrypted token (cryptography),SqliteStoreon stdlibsqlite3throughasyncio.to_thread, tables and indexes of the design,retention_sweep.- Depends on: 8, 9
- Requirements: R11.1–R11.4, retention
- Test: T1 —
tests/unit/persistence/test_sqlite.py(put/get/query, write failure surfacesStoreWriteError, sweep deletes expired rows); T8 —test_push_token_encrypted_at_rest
- [x] 28. Channels: entity,
A2AChannel,HelpNeed/HelpDecisionharness/channels/:Channelentity,ChannelMessage, membership check (ChannelMembershipError),A2AChannelemitting the channel data part, channel extension schema underdocs/a2a/ext/channel.json;help.decided.indefault body (LLM structured output) and its validator.- Depends on: 23, 15, 27
- Requirements: R12.1, R12.4, R13.1–R13.4
- Test: T8 —
test_non_member_rejected_without_task_existence; T1 — help decision validator; T3 — channel schema
- [x] 29. Core loop runner (in-process, no Temporal yet)
harness/core/loop.py: the five-line loop over anOperationsport (assemble, invoke LLM, invoke tool, compact, persist, emit) so Layer 5 binds it to activities; tool-call extraction as a pure function; completion predicatetask.complete.inwith the unresolved-sub-task wait; intrinsic bodies forcreate_plan,complete_step,ask_participant,create_task_for_participant,spawn_subtask,set_participant_role(admin-only),emit_uiplaceholder.- Depends on: 25, 26, 28, 21
- Requirements: R8.4, R8.5, R9.2, R9.3, R12.2, R12.3, decision-004
- Test: T1 —
tests/unit/core/test_loop.pywithFakeLLM(loop terminates, plan attached, help request moves toINPUT_REQUIRED); T8 —test_role_change_requires_admin
- [x] 30. Hook-wrapped operation runner
- The activity-shaped wrapper that runs
pre/in/postaround each operation with the redactor on inputs and outputs; used by Layer 5's activities and by the in-process runner. - Depends on: 5, 9, 29
- Requirements: R2.2–R2.4, R2.11, abuse case 6
- Test: T1 —
tests/unit/hooks/test_wrapper.py; T8 —test_ingress_redacted_before_history(wrapper variant)
- The activity-shaped wrapper that runs
Layer 5 — durable execution, A2A server, inbox, heartbeat (branch loop/issue-3-l5-service)
- [x] 31. Temporal client, worker, data converter, search attributes
service/durable/client.py,worker.py:Client.connectwith API key, TLS,pydantic_data_converter,TracingInterceptor; worker registration of workflows and activities; search attributesA2AContextId,A2ATaskState,TinyHarnessAgent; the time-skipping test environment fixture.- Depends on: 8, 30
- Requirements: R19.9–R19.11
- Test: T2 —
Feature: Durable core loop,Scenario: a task runs the loop to completion with recorded activity results(first scenario, with the activities of task 32)
- [x] 32. Activities
assemble_context,invoke_llm,invoke_tool,compact,persist,send_channel_message,emit_event,dispatch_hooks,intake,run_remote_agent_turn,poll_channels,monitor_snapshot,retention_sweep, each the hook-wrapped body of task 30 with heartbeats where the design says.- Depends on: 31
- Requirements: R19.1, R19.6
- Test: T2 — as task 31; T1 — each activity against fakes
- [x] 33.
TaskWorkflow: loop, mailbox, retries, completion, rolloverrun,inboxupdate,cancelsignal,taskandevents_sincequeries; workflow-managed attempts with hooks between them;wait_conditionforINPUT_REQUIRED;TaskStartrollover withall_handlers_finished; the durable event log with monotonic sequence; child workflows for sub-tasks; sandbox pass-through list.- Depends on: 32, 29
- Requirements: R19.2–R19.5, R19.7, R19.8, R15.3–R15.5, R8.5
- Test: T2 —
Scenario: a worker crash mid-activity resumes without a second LLM call;Scenario: a non-idempotent tool failure is not retried;Scenario: activity.failed and activity.retried hooks run between workflow-managed attempts;Scenario: an inbox message to an executing task is drained at the next iteration;Scenario: compaction runs before the LLM call when the first message is over budget;Scenario: continue-as-new carries the mailbox, event log and pending help request;Scenario: a parent waits for an unresolved sub-task before completing
- [x] 34. Help requests end to end
ask_participant→ channel message →INPUT_REQUIRED→ reply update → resume;create_task_for_participant→ child workflow linked as sub-task.- Depends on: 33, 28
- Requirements: R12.2, R12.3, R12.5, R12.6
- Test: T2 —
Feature: Help requests,Scenario: a reply on the channel resumes an INPUT_REQUIRED task;Scenario: a need that blocks on another participant's work creates a sub-task
- [x] 35. Remote agents and
RemoteTaskWorkflowharness/agents/remote.pyona2a-sdk'screate_client/A2ACardResolver,A2A-VersionandA2A-Extensionsheaders, required-extension refusal;RemoteTaskWorkflowrelaying status updates into the parent's sub-task record.- Depends on: 33
- Requirements: R7.1–R7.5, abuse case 5
- Test: T2 —
Feature: Remote agents,Scenario: delegation to a remote A2A agent tracks the sub-task state; T8 —test_remote_card_with_unknown_required_ext_refused
- [x] 36. A2A server: app, card, executor, request handler, task store, bridge
service/a2a/:create_appmounting the three route sets,build_agent_cardfrom the entity with the three extensions,HarnessExecutor(redact → update-with- start → bridge →TaskUpdater),HarnessRequestHandlerwithon_subscribe_to_taskandAccessPolicyon every task operation,TemporalTaskStore,PollingEventBridge, size/rate middleware, unadvertised-extension rejection,StorePushConfigStore+BasePushNotificationSender,EventEnvelopeintake.- Depends on: 33, 27
- Requirements: R14.1–R14.9, R15.1, R15.2, R15.6, abuse cases 2, 4, 7
- Test: T2 —
Feature: A2A server:Scenario: SendStreamingMessage streams a Task then status updates through the bridge;Scenario: GetTask and ListTasks read the workflow;Scenario: an unadvertised extension is rejected;Scenario: returnImmediately returns after the task exists;Scenario: push notification configs receive status updates;Scenario: cancel emits CANCELED;Scenario: SubscribeToTask after a server restart replays the event log; T8 —test_foreign_task_get_list_subscribe_cancel_not_found,test_oversized_request_not_persisted,test_ingress_redacted_before_history; T6 — agent card snapshot
- [x] 37. Heartbeat schedule and workflow
service/heartbeat.py: schedule creation (ScheduleActionStartWorkflow,ScheduleIntervalSpec),HeartbeatWorkflowrunningpoll_channels,monitor_snapshot,retention_sweep;GET /_monitor; CLIschedules delete.- Depends on: 32, 36
- Requirements: R16.1–R16.5
- Test: T2 —
Feature: Heartbeat,Scenario: a schedule tick forwards a pull-channel message to its task
- [x] 38. CLI entry points
tiny-harness serve|worker|tui|schedules|tasks purge(argparse, stdlib), wired toSettings;tasks purgedeletes rows and terminates the workflow.- Depends on: 36, 37
- Requirements: R21, retention
- Test: T1 —
tests/unit/test_cli.py(argument parsing, missing secret exits non-zero with the variable name)
Layer 6 — observability plugin (branch loop/issue-3-l6-o11y)
- [x] 39. o11y plugin
service/o11y/: oneHookExecutoron everypre/postpoint opening and closing spans with GenAI semantic-convention names and attributes, structured logging with task/correlation ids, OTLP exporter configuration, Langfuse endpoint option, redactor over attributes and fields; MCP and Temporal context propagation verified.- Depends on: 33, 36, 9
- Requirements: R17.1–R17.6
- Test: T2 —
Feature: Observability,Scenario: one span per operation with GenAI attributes crosses the workflow boundary(in-memory span exporter); T1 — log record shape
Layer 7 — A2UI and the TUI renderer (branch loop/issue-3-l7-tui)
- [x] 40. A2UI models, vendored schemas,
emit_ui, action intakeinteraction/a2ui/: the six message models, vendored 0.9.1 schemas with attribution,jsonschemavalidation, the A2UI extension declaration in the card (supportedCatalogIds,acceptsInlineCatalogs),emit_uibody, action intake with surface/component registry.- Depends on: 29, 36
- Requirements: R20.5, abuse case 9
- Test: T1 —
tests/unit/a2ui/test_messages.py(valid/invalid payloads); T8 —test_unknown_a2ui_action_discarded; T6 — card snapshot gains the extension
- [x] 41. Surface and renderer entities
interaction/surface.py,renderer.py:Modality,Surface,Rendererwithsupportedand placeholderRenderPlan.- Depends on: 4
- Requirements: R20.1, R20.4, R20.8
- Test: T1 —
tests/unit/interaction/test_renderer.py(placeholder for unsupported kind)
- [x] 42. TUI renderer (Textual)
interaction/tui/: the app ofdesign/tui-renderer.html(conversation pane, task/plan/trace tabs, composer, key bindings), ana2a-sdkclient over JSON-RPC with streaming andA2A-Version: 1.0,SubscribeToTaskper open task, the basic catalog mapped onto Textual widgets (RadioSetfor ChoicePicker, placeholder for Video/AudioPlayer),pytest-textual-snapshotadded as a dev dependency.- Depends on: 40, 41, 36
- Requirements: R20.2, R20.3, R20.6
- Test: T5/T6 —
tests/ui/test_tui_snapshots.py(each prototype state); T9 —tests/ui/test_tui_keys.py
Layer 8 — web renderer (branch loop/issue-3-l8-web)
- [x] 43. Web renderer scaffold and generated types
renderers/web/with Vite, TypeScript strict, React 19, Bun;json-schema-to- typescriptgenerating types fromdocs/a2a/ext/*.jsonat build;bun run build/test/test:visual/test:a11yscripts; CI job.- Depends on: 23, 28, 40
- Requirements: R20.2, R22
- Test: T13 —
bun run --cwd renderers/web buildandtsc --noEmitgreen in CI
- [x] 44. Web renderer app
- The app of
design/web-renderer.html: REST binding with SSE (message:stream,tasks/{id}:subscribe),A2A-Version: 1.0, event stream, task/plan/trace pane from the task extension, composer, help-request state, placeholder for unsupported parts, design tokens as CSS variables. - Depends on: 43
- Requirements: R20.2–R20.4
- Test: T5 — Playwright visual tests against the prototype states (
test:visual); T9 — axe-core and keyboard walk (test:a11y)
- The app of
- [x] 45. A2UI in the web renderer
@a2ui/react+@a2ui/web_core:MessageProcessorfed withapplication/a2ui+jsonparts,A2uiSurfacewithbasicCatalog, actions sent back as A2A messages with the A2UI part.- Depends on: 44
- Requirements: R20.5, R20.6
- Test: T5 — the A2UI card state rendered by the official renderer; T2 —
Scenario: an A2UI action from the web renderer reaches the task
Layer 9 — demo, docs, capability docs, verification (branch loop/issue-3-l9-demo)
- [x] 46. Demo plugin and configuration
examples/demo/: plugin with theordersandpolicystdio MCP servers (theorders.get_ordertool idempotent), asupport-agentskill,config.toml, the "refund order #48213" script,tests/e2e/test_demo.pyandtest_crash_recovery.py(two kill points), both markede2e.- Depends on: 38, 42, 45
- Requirements: R24.1–R24.6, R19.11, R18.5
- Test: T4, T12 —
uv run pytest tests/e2e -q -m e2e
- [x] 47. Deployment and getting-started documentation
- Docs site pages: getting started with the demo, deployment guide (perimeter requirement, Temporal Cloud retention, trace backend retention, the keyring lookups), the extension schemas published under
docs/a2a/ext/; README updated. - Depends on: 46
- Requirements: non-functional Documentation, decision-003
- Test: T13 —
bun run docs:buildgreen; markdownlint
- Docs site pages: getting started with the demo, deployment guide (perimeter requirement, Temporal Cloud retention, trace backend retention, the keyring lookups), the extension schemas published under
- [x] 48. Capability docs
- One doc per requirement group under
docs/capabilities/with history rows to this spec and decisions 002–004;capabilities.mdandarchitecture.mdupdated;evidence/documentation.mdwritten. - Depends on: 47
- Requirements: the-loop's capability-docs gate
- Test: T13 — markdownlint; the
capability-docsnode's gate
- One doc per requirement group under
- [x] 49. Verification run and evidence
- Execute
testing-plan.md's activities in order, record each command, outcome and evidence underevidence/(redacted), tick the activities, fill Verification results. - Depends on: 46, 48
- Requirements: all, through the plan
- Test: every row of
testing-plan.md
- Execute
Dependency graph (DAG)
Order of execution: Layers 1 → 9 in sequence; within a layer, tasks run in the order listed except where the graph shows independence (for example 8 and 9 beside 3–7; 15–18 beside 19–22; 27 and 28 beside 23–26), which the executor may use to interleave.
Checkpoints
At which task boundaries the-loop runs tests/validations. Record each task's test command and its red→green transition in the commit that carries it — the harness keeps the transcript and git keeps the commits, so no progress log is written (issue-365). After the last task, the verification node executes testing-plan.md — ticking each activity and recording its command, outcome and committed evidence — and only then do the review phases run the self/critic rounds AND the security review gate (recorded in evidence/security-review.md) before the work item can be marked ready.
- Every task: the task's own test red→green, then
uv run pre-commit run --all-files(ruff, pyright strict, unit tests, markdownlint, theAnygate). - Every layer (before its PR is opened):
uv run pytest tests/unit tests/contract tests/security -q, plustests/integrationfrom Layer 5 on, plustests/uifrom Layer 7 on, plusbun run --cwd renderers/web testfrom Layer 8 on; the layer's PR is opened as a stacked PR against the previous layer's branch and recorded inevidence/pull-requests.md. - After Layer 9: the verification node runs the whole plan, including the e2e demo on Temporal Cloud and the crash-recovery run.
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.