Skip to content

(MOT-4162) harness: minimal identity prompt + on-demand agent playbook skills#558

Open
rohitg00 wants to merge 4 commits into
mainfrom
harness-minimal-prompt
Open

(MOT-4162) harness: minimal identity prompt + on-demand agent playbook skills#558
rohitg00 wants to merge 4 commits into
mainfrom
harness-minimal-prompt

Conversation

@rohitg00

@rohitg00 rohitg00 commented Jul 22, 2026

Copy link
Copy Markdown
Contributor

What

  • prompts/default.txt shrinks from ~9,450 to 1,676 tokens (tokenizer-measured via context::count-tokens). The universal call loop, discovery surface, payload and error rules, security, and conventions stay.
  • The orchestration, finishing, and building playbooks move verbatim into skills/orchestration.md (3,686 tok), skills/finishing.md (2,362 tok), and skills/building.md (1,172 tok). iii-directory already serves worker-shipped skills, so agents pull them as harness/orchestration, harness/finishing, harness/building. The prompt instructs: pull the matching playbook BEFORE the first action of that kind, once per session.
  • prompt/tests.rs keeps every content invariant. Tests for moved sections now pin the skill files via include_str!, so the doctrine stays test-locked exactly as before; two new tests pin the skill pointers and playbook contents.
  • One content fix in the orchestration playbook: an explicit rule that the FINAL stage of a join must OMIT metadata.session_id so the composed result delivers back into the registering chat. In live testing an agent pinned it and the answer landed in a side session.

Why

  • 63% of the identity prompt is the orchestration playbook. Sessions that never spawn pay it on every generation.
  • Seven provider workers ship near-copies of the same prompt (28 to 32 KB each, already drifted apart). Moving the bulk into versioned skills gives one canonical copy; a follow-up PR points the provider identities at the same minimal core.
  • The fp worker already proved the pattern in the other direction: its pipe guidance moved out of the prompt variants into a presence-gated pre-generate hook. This PR does the same for the playbooks, with on-demand pull instead of per-turn injection.

Test evidence

Live A/B on a rig (engine 0.21.6, harness 1.4.2, claude-sonnet-5, 13 sessions): identical task set, baseline identity prompt vs this minimal core via the router operator override.

metric baseline minimal core
system tokens per generation 7,850 2,371 (fp hook injection included in both)
simple task (ls, workers query, registry lookup) correct correct, zero skill pulls, fewer turns
fan-out task (3 children, state writes, report) correct correct; agent pulled harness/orchestration before its first engine::register_trigger and harness::spawn, unprompted
conventions (FAILED: first line, @fn pills) partial held

Note: the rig ran harness 1.4.2, where an in-turn spawn still parks and returns the child result; the playbook text intentionally keeps the 1.5.x fire-and-forget doctrine and was not weakened by that observation.

Rollout

  • default.txt is the router-absent fallback, so this PR alone changes behavior only on rigs without a provider identity prompt.
  • Skills ship with the bundle; iii-directory picks them up on install (auto_download covers new adds).
  • Follow-ups: provider identity prompts unify on the same core; iii-directory gains an optional pre-generate hook injecting a compact skills index for automatic discovery.

Draft: direction review wanted before the provider prompts move.

Linear

Closes MOT-4162. Part of MOT-4157.

Coordination

Summary by CodeRabbit

  • Documentation

    • Streamlined agent guidance with clearer function discovery, contract retrieval, JSON-object payload requirements, and categorized error-handling with retry/fix instructions.
    • Added on-demand agent playbooks for orchestration, finishing fan-out runs, and building/registering workers, including stricter trigger and completion-wiring expectations.
    • Updated trigger and finish/checklist guidance, including wake-up invariants, deadline fallbacks, and SDK/documentation reference requirements.
  • Tests

    • Updated prompt validation to match the new playbook-based workflow and revised documentation references.

@vercel

vercel Bot commented Jul 22, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
workers Ready Ready Preview, Comment Jul 23, 2026 4:21pm
workers-tech-spec Ready Ready Preview, Comment Jul 23, 2026 4:21pm

Request Review

@coderabbitai

coderabbitai Bot commented Jul 22, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 4ae804ca-1090-404f-898d-c835ae7ada39

📥 Commits

Reviewing files that changed from the base of the PR and between ae9db57 and 5968bda.

📒 Files selected for processing (2)
  • harness/prompts/default.txt
  • harness/skills/finishing.md
🚧 Files skipped from review as they are similar to previous changes (2)
  • harness/skills/finishing.md
  • harness/prompts/default.txt

📝 Walkthrough

Walkthrough

The default harness prompt now enforces contract-first function calls and delegates orchestration, finishing, and building guidance to on-demand skill playbooks. Prompt tests load these playbooks directly and validate their key invariants.

Changes

Harness playbook extraction

Layer / File(s) Summary
Prompt contract and skill dispatch
harness/prompts/default.txt, harness/skills/SKILL.md
Function discovery, contract retrieval, JSON-object payloads, categorized retries, security rules, and on-demand skill loading are consolidated in the prompt and skill index.
Orchestration and finishing playbooks
harness/skills/orchestration.md, harness/skills/finishing.md
Playbooks define trigger-based fan-out, reactions, joins, completion signaling, deadlines, and end-of-run handling.
Worker building workflow
harness/skills/building.md
The building playbook documents worker discovery and installation, coder-backed edits, worker registration, and SDK reference requirements.
Playbook and prompt invariants
harness/src/prompt/tests.rs
Tests load playbooks directly and validate prompt allowlists, skill pointers, workflow guidance, SDK references, orchestration, finishing, and capability ordering.

Estimated code review effort: 2 (Simple) | ~10 minutes

Possibly related PRs

  • iii-hq/workers#460: Updates related function discovery, contract retrieval, and denied-function prompt guidance.
  • iii-hq/workers#540: Introduces orchestration semantics reflected in these harness playbooks.

Poem

I’m a rabbit with playbooks tucked neat,
Contracts and triggers now march to a beat.
Fan-outs hop onward, completion shines bright,
Builders read SDKs before taking flight.
Tests guard each burrow—what a delightful sight!

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly reflects the main change: shrinking the harness identity prompt and moving agent playbooks to on-demand skills.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch harness-minimal-prompt

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@github-actions

Copy link
Copy Markdown
Contributor

skill-check — worker

0 verified, 47 skipped (no docs/).

Layer Result
structure
vale
ai
render

Four for four. Nicely done.

The docs moved SDK references from /docs/api-reference/sdk-* to
/docs/reference/sdk-*, and the engine wire protocol page lives at
/docs/reference/engine-protocol; the old paths 404. Verified live:
old paths return 404, new paths return 200 and serve markdown with
the .md suffix. Updated the playbook and the prompt invariants that
pin the URLs.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@harness/prompts/default.txt`:
- Around line 21-35: Update the discovery and contract-retrieval instructions in
Steps 1–2 to apply only to undocumented function ids. Explicitly exempt
documented calls such as directory::skills::get, registry calls, and
harness::react trigger targets, while preserving the existing discovery
requirements for all other functions and the documented batching and re-fetch
exceptions.

In `@harness/skills/finishing.md`:
- Around line 21-26: Update Step 3 in the validator registration guidance to
limit parent_session_id filters to children spawned within the current turn. For
trigger-fired or direct-spawn fan-outs without parent links, require per-child
session_id subscriptions or state-key joins so completions reach the validator
and turn_complete is written.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 99bdfe6e-1087-42d2-8041-d3ab40a3180f

📥 Commits

Reviewing files that changed from the base of the PR and between 53ef04c and ae9db57.

📒 Files selected for processing (6)
  • harness/prompts/default.txt
  • harness/skills/SKILL.md
  • harness/skills/building.md
  • harness/skills/finishing.md
  • harness/skills/orchestration.md
  • harness/src/prompt/tests.rs

Comment thread harness/prompts/default.txt Outdated
Comment on lines +21 to +35
Step 1. Find the id. Call `engine::functions::list` with `{ search: "<name>" }` or
`{ prefix: "<worker>::" }` or `{ worker: "<name>" }`. The one-line description is a hint,
not the contract.

Step 2. Get the contract. Call `engine::functions::info` with the id you found, e.g.
`{ function_id: "shell::fs::ls" }`. The answer is the API reference: the request schema, the
response schema, the description, the owning worker, and the bound triggers. BEFORE the FIRST
call to a function this session, you must do this step. The `function_id` must be the function
you want to call. Never pass `engine::functions::info` itself or any `engine::*` / `worker::*`
discovery function as the id — that only returns metadata about the info function (worker
`iii-engine-functions`). The discovery functions are documented here; never introspect them.
If you forget the `function_id` argument, the call fails with `missing field`. A contract you
fetched earlier this session stays valid — do not fetch it again before later calls; fetch it
again only when a call fails with `invalid_arguments` / `serialization error` / a missing
field, or a registry-change notice appears. Need more than one contract at once? Pass
`{ function_ids: ["a::b", "c::d"] }` and it returns `{ functions: [...] }`, one per id — one
call, never one per id.

Step 3. Call the function. The `payload` is a JSON OBJECT, never a string. Match the
contract exactly: every required field, no extra fields, and the right value formats
(single binary vs argv array, inline string vs base64, "K=V" entries). Guessing field names
burns turns and can put workers into degraded states. If a value is long or multi-line
(source code, JSON, markdown), it is still just a string VALUE of one field — do not turn the
whole payload into a string.

Step 4. If you get an error, read it and change something. Never send the same `function` +
`payload` again unchanged.

<example>
user: List the files under /tmp.
assistant: [calls engine::functions::list { search: "ls" } and finds shell::fs::ls]
[calls engine::functions::info { function_id: "shell::fs::ls" } to get the contract]
[calls agent_trigger with function: "shell::fs::ls", payload: { path: "/tmp" }]
</example>

# Payload rules

The most common mistake is sending `payload` as a JSON-encoded string. The worker rejects it
with `invalid_arguments` / `serialization error: invalid type: string ..., expected struct`.
`{ function_id: "shell::fs::ls" }`, BEFORE the FIRST call to a function this session.
The answer is the API reference: the request schema, the response schema, the
description, the owning worker, and the bound triggers. A contract you fetched stays
valid all session — re-fetch only after `invalid_arguments` / `serialization error` / a
missing field, or a registry-change notice. Need several at once? Pass
`{ function_ids: ["a::b", "c::d"] }` — one call, never one per id. If you forget the
`function_id` argument, the call fails with `missing field`. Never pass an `engine::*` /
`worker::*` discovery function as the id — that only returns
metadata about the info function; the discovery functions are documented here, never
introspect them.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Make the discovery loop explicit about documented exceptions.

These lines require discovery and contract retrieval for every function, but the loaded skills explicitly require direct use of documented calls such as directory::skills::get, registry calls, and harness::react as a trigger target. Agents following one rule will violate the other. Narrow this rule to undocumented function ids and enumerate the documented exceptions.

Proposed clarification
- Before every call: did I find the id with `engine::functions::list` ...
+ Before every call to an undocumented function: did I find the id with
+ `engine::functions::list` and retrieve its contract?
+ Use function ids explicitly documented in this prompt or a loaded skill
+ directly, including documented skill/registry calls and trigger targets.

Also applies to: 116-120

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@harness/prompts/default.txt` around lines 21 - 35, Update the discovery and
contract-retrieval instructions in Steps 1–2 to apply only to undocumented
function ids. Explicitly exempt documented calls such as directory::skills::get,
registry calls, and harness::react trigger targets, while preserving the
existing discovery requirements for all other functions and the documented
batching and re-fetch exceptions.

Comment thread harness/skills/finishing.md
…caveat

Step 2 now states explicitly that functions documented in the prompt
(the discovery functions and directory::skills::get) skip the find-id
and get-contract steps; everything else keeps the full discipline.

finishing.md Step 3 documents the parent_session_id boundary: the
filter only matches children that carry the parent link (direct spawns
from the session, or reaction spawns whose metadata names it).
Reaction- or wave-dispatched children without the link need the
run-scope state keys or an explicit per-child join, otherwise their
completions never reach the validator and turn_complete is never
written.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant