Skip to content

A procedure it follows

Ask a model the same question twice and it will take two different routes to the answer. Where there is a right way to do something — a research procedure, an incident runbook, a compliance check — that variability is the problem.

A procedure is that method, written down, which the agent navigates instead of inventing one.

Procedure and mission are the same thing. These pages say procedure; the CLI flags and log lines say mission (--mission, runs ONE mission (sealed)).

A mission has two lives, and both matter:

in the workspacea build session. You describe what you want, it takes shape beside the conversation, and what you settle on is saved as the cards below
sealed onto a runnera fixed procedure. An outside caller asks a question and gets that method every time, and cannot ask for a different one

The first is how you make one; the second is how you ship it. This page is what sits in between — the cards themselves, which are worth being able to read even though you did not type them.

Three things, and the agent reads all three:

partfilewhat it does
the map_flowchart.mdwhich card handles which kind of question
the cardsone .md eachthe actual steps for one kind of question
the fence_manifest.mdwhat this procedure may touch, and nothing else
My_Workflow/
sources/
_flowchart.md the map
_manifest.md the fence
find-case-law.md a card
lookup-statute-text.md a card
chunks.jsonl searchable index, built from the above
vectors.bin

The agent searches a procedure the way it searches anything else: it finds the map, locates the question on it, walks to the right card, and executes that card’s steps in order.

Three node shapes carry meaning:

shapemeans
[(name)]search or read a collection of documents
[[method: x]]apply a rule defined in the card
{question}a decision the model makes
## card: find-case-law
id: find-case-law
intent: "Find decided cases on a point of law"
match_cues: ["find a case", "is there authority", "what did the court hold"]
domain: legal
resources:
memories: ["judgments", "judgment-full-text"]
methods:
- id: terminology-variations
kind: rule
apply: "The question may use everyday words where the source uses terms of art.
Search several phrasings before concluding nothing exists."
steps:
- n: 1
do: "Search the judgments collection for the proposition"
via: "memory: judgments"
extract: "<hits> - candidate cases with their ids"
then: "step 2"
- n: 2
do: "Read the full text of the most relevant case"
via: "memory: judgment-full-text"
query: "<case_id>"
extract: "<holding> - what the court actually held"
then: "step 3"
- n: 3
do: "Confirm the holding answers the question as asked"
via: "ai: verify relevance"
then: "branch: found -> return, more candidates -> step 2, none -> ask user"
dos:
- "Cite the case id with every proposition"
- "Read the full text before relying on a summary"
donts:
hard:
- "do NOT query the full-text collection with a question - it takes ids only"
soft:
- "do not stop at the first plausible case"
done_check: "A holding, with its case id, that answers the question as asked"
fieldwhat it is for
idhow the map refers to this card
intentone line: what this card is for. The model matches on this
match_cuesphrasings that should land here. Write how people actually ask
resources.memorieswhich collections this card may use — must also be in the fence
methodsnamed rules the steps refer to, so a rule is written once and reused
stepsthe procedure. do = what, via = with which resource, query = what to send it, then = where next
dos / dontshard is never to be done; soft is a strong preference
done_checkhow the agent knows it is finished — not “did it try” but “does it have the answer”

via: names the resource; query: says what to send it. A step that names a collection without saying what to pass has been observed to make the model invent a call that does not exist, get an error, and answer from partial results instead.

## memories
judgments
judgment-full-text
case-summaries
## commands
(none)

The runner may use only what is listed here. Not “should” — may. Combined with exec-policy enforce ON, NO cmdset, a procedure that lists no commands cannot run a shell at all.

This is what makes a procedure safe to expose to callers you do not control: they choose the question, never the method, and the method cannot reach outside its fence.

You do not hand-author these files.

In the workspace, start a new session on a mission engine rather than chat. Then describe what you want in conversation — what question arrives, what should be searched, what must never happen. It takes shape in the panel beside the conversation as you talk, you correct it in the same conversation, and each revision is saved and re-indexed as you go.

The YAML above is what it produces. You need to be able to read it — to check a step goes where you meant — but you do not need to write it.

That matters because the person who knows the procedure is rarely the person who wants to write YAML.

Cards accept an examples: block, and it is tempting to paste in a worked example with its answer.

Measured. A card carried one example: a question, its answer, and the source id. Asked that exact question, the agent found the card, read the answer straight out of it, and returned in three steps without searching anything. It looked like excellent retrieval. It was recitation.

With the example removed, the same question took thirty-nine steps, searched honestly, and got it wrong — which had been the true state all along.

Examples teach shape. One that carries a real answer stops you measuring the system and starts you measuring the card.

Terminal window
hexaeight-activate agskill-export --mission My_Workflow --out mission-My_Workflow.zip
hexaeight-activate agskill-import --in mission-My_Workflow.zip --root ~/.hexaeight-harness

The bundle carries the cards, the map and the fence. It does not carry the document collections they search — those must already exist on the target — and permissions never travel, because they are specific to an identity.

Import refuses to overwrite: mission memory exists (use --force to overwrite). Without --force nothing happened and the previous version is still the one running.

Check what a bundle holds before trusting it:

Terminal window
unzip -l mission-My_Workflow.zip

The card count is the number of .md files under sources/ minus _flowchart.md and _manifest.md, which are not cards.

An agent can be sealed so it runs exactly one procedure, and a caller cannot choose another:

Terminal window
hexaeight-activate engine --add runmission --name my-engine \
--mission My_Workflow \
--model "<route|model>" --router "<agent|url>" \
--dir <agent-dir> --file <wrapper>

--file names a small wrapper script that sits in front of the engine. You do not write it: add-external-agent creates it when it provisions a runner, in a folder beside the runner’s own. Its job is to impose this door’s procedure on every turn and strip anything a caller sends that tries to choose a different one.

It must live outside the agent’s folder, because each turn runs with that folder masked — a script kept inside it does not exist as far as the engine is concerned.

Proof at startup:

[hexaeight-agent] engine 'my-engine' runs ONE mission (sealed): My_Workflow

If that line is absent the procedure is not sealed, and the agent will run whatever a caller asks for. See Other software calling it.

symptomcause
it answers without searchingan examples: block contains the answer
it invents a call and failsa step names a resource but no query
it cannot reach a collectionmissing from the fence, or from resources.memories
an edit has no effectthe index was refreshed rather than rebuilt — see Troubleshooting
a caller ran a different procedurethe engine was re-sealed without --file, unbinding the wrapper