Skip to main content

IntentText for Agents

AI agents produce Markdown. Markdown has no structure for workflows, no typed blocks, no audit trail, no trust chain.

IntentText gives agents a small set of canonical workflow keywords that produce documents machines can execute and humans can read. The executor enforces gate checks and policy rules before a single step runs.

Why not JSON or YAML for tool calls?

The reflex for "structured agent output" is a JSON or YAML tool-call payload. That works for one machine handing data to another, but it is not a document: a human can't read a 500-line JSON pipeline, it has no audit trail, no approval gates a person can sign, and nothing makes it tamper-evident. A .it workflow is both — the same file an agent executes, a human reviews and approves, and anyone verifies offline:

JSON / YAML tool call.it workflow
Machine-executableYesYes (executeWorkflow)
Human-readable as a documentNoYes — typed lines, renders to HTML/PDF
Human approval gatesNogate: / route: / require:
Tamper-evident audit trailNohash-chained approve: + sign:/freeze:
Self-verifiable offlineNoverifyDocument / verifyAuditChain
Self-validatingSchema, externalcheckConformance(source)

The payoff: one artifact is the plan, the human gate, and the sealed record. No second system holds the approval state, the audit log, or the signed copy — they all travel inside the file the agent produced.

The workflow keywords

Nine canonical keywords (the agent tier) cover the full agent workflow lifecycle:

KeywordPurpose
step:A unit of work — the primary building block
decision:Conditional branching — if/then/else
gate:Hard checkpoint — execution blocked until the condition is satisfied
trigger:Event-based activation
result:Terminal workflow outcome
policy:Rule declaration — constraints the executor enforces before running
audit:Immutable audit log entry
ask:A question the workflow must resolve (human or model)
context:Agent execution context — goal and constraints

Approval routing (contract tier). When a workflow needs named human approvers, declare them in-file with route: / require:workflowState(source) then derives who's pending and who's next, purely from the file. See Approval Workflows.

route: sequential
require: engineering-manager
require: security | when: touches_prod = yes

Related task keywords: task: / done: — task tracking.

Extended workflow keywords (for complex orchestration):

Looping, parallel execution, handoff, retry, wait, checkpoint, and other advanced workflow primitives are available in the x-agent: extension namespace. See Extension keywords →.


Executing a workflow

Use executeWorkflow() from @dotit/core to run a document against a runtime. The executor evaluates policy: blocks first — if a required gate is unmet, execution returns policy_blocked without running any steps.

import { parseIntentText, executeWorkflow } from "@dotit/core";

const doc = parseIntentText(source);

const result = await executeWorkflow(doc, {
// Tool handlers, keyed by each step's `tool:` value. Receive (input, context).
tools: {
validate: async (input, context) => ({ ok: true }),
infra: async (input, context) => "provisioned",
},
// Called when a gate: block is reached — resolve true (approve) or false (reject)
onGate: async (gate, context) => true,
options: { dryRun: false },
});

console.log(result.status); // "completed" | "gate_blocked" | "policy_blocked" | "error" | "dry_run"
console.log(result.context); // collected step outputs
console.log(result.log); // one entry per processed block

Execution result statuses

StatusMeaning
completedAll steps executed successfully
gate_blockedA gate: check returned passed: false — halted at that gate
policy_blockedA policy: requires: gate was not satisfied before execution started
errorA step threw an unhandled exception
dry_runRuntime dryRun: true — returns plan without execution

A complete agent task plan

title: Data Migration Pipeline
context: agent | goal: Migrate customer data from legacy DB | constraints: Zero downtime, max 4 hours

policy: Migrations require manager approval | requires: gate | gate: manager-approval

section: Preparation
step: Export legacy data | id: export | tool: pg_dump | timeout: 30m
step: Validate export | id: validate | depends: export | tool: checksum_verify

section: Migration
gate: Manager approval | id: manager-approval | approver: engineering-manager | timeout: 72h
step: Create backup | id: backup | depends: manager-approval | tool: pg_backup
step: Run migration scripts | id: migrate | depends: backup | tool: flyway
decision: Migration successful? | if: migrate.exit_code == 0 | then: verify | else: result-fail

section: Verification
step: Verify row counts | id: verify | depends: migrate | tool: row_counter
step: Run integration tests | id: test | depends: verify | tool: pytest
audit: Migration complete | by: DataBot | at: {{now}} | action: migrate
result: Success | status: completed

section: Rollback
result: Migration failed — rollback initiated | id: result-fail | status: error
step: Restore backup | depends: result-fail | tool: pg_restore

Gates and decisions

gate: blocks execution until a condition is satisfied:

gate: Approval received | id: approval | approver: engineering-manager | timeout: 72h

decision: branches the workflow based on a condition:

decision: Budget approved? | if: budget.amount <= 10000 | then: auto_approve | else: manager_review

Gates are evaluated by the checkGate handler in your runtime. If gate: returns passed: false, executeWorkflow returns { status: "gate_blocked", blockingGate: "approval" }.


Policy enforcement

policy: blocks declare constraints the executor enforces before any step runs:

policy: No production writes without approval | requires: gate | gate: prod-approval | action: block
policy: All migrations require a backup step | requires: step | id: backup

If a required gate has not passed, the executor returns policy_blocked without touching any steps. No partial execution — either the policy allows the run, or nothing runs.


Self-validate before handing off

An agent should check its own output before passing it on. checkConformance is read-only (it never rewrites the document) and reports structural + semantic issues:

import { checkConformance } from "@dotit/core";

const { conformant, errors, warnings } = checkConformance(generatedSource, { level: "lax" });
if (!conformant) throw new Error(`generated invalid .it: ${errors.map((e) => e.message).join("; ")}`);

Use lax (no error-level issues) as a hard gate; strict (no warnings either, e.g. every date ISO 8601) when you certify a spotless artifact. Unknown keywords are never errors — an agent can invent domain vocabulary and still produce a conformant document.

Audit logging — and making the order tamper-evident

Agents write audit: blocks to build a record of what was executed, by whom, and when:

audit: Fetched 12,450 records | by: DataBot | at: 2026-03-06T02:15:00Z | action: export
audit: Migration complete — 0 errors | by: DataBot | at: 2026-03-06T03:45:00Z | action: migrate

For approvals, go one step further: the hash-chained audit trail makes the order tamper-evident, so nobody can insert, delete, or reorder an approval after the fact. appendApproval links each approve: line to the previous via prev: sha256:…, and verifyAuditChain reports the first broken link:

import { appendApproval, verifyAuditChain } from "@dotit/core";

let src = appendApproval(plan, { by: "DataBot", role: "agent", note: "Pre-flight checks passed" });
src = appendApproval(src, { by: "Sarah Chen", role: "engineering-manager", note: "Approved" });

verifyAuditChain(src); // { valid: true, length: 2, chained: 2 }

Seal the plan after the approvals (approve: is part of the hashed body), and the seal protects the body while the chain protects the order — together, the whole agent-plus-human decision record is tamper-evident. See Approval Workflows.

Query the audit trail:

dotit query ./logs --type audit --by DataBot --format table

MCP server integration

The IntentText MCP server gives agents direct access to .it files without the need to import @dotit/core directly:

npm install @dotit/mcp

Available MCP tools:

ToolPurpose
parse_intent_textParse a .it source to JSON
render_htmlRender to styled HTML
render_printRender to print-ready HTML
query_documentQuery blocks with filters
merge_templateMerge a template with data
seal_documentSeal a document (sign + freeze)
verify_documentVerify integrity
compute_hashCompute the canonical SHA-256 document hash
validate_documentSemantic validation beyond syntax
diff_documentsDiff two document versions
document_to_sourceConvert JSON back to .it source
extract_workflowExtract the execution graph
get_document_historyRead a tracked document's history
generate_signing_keyGenerate an Ed25519 keypair (identity layer)
sign_documentAdd an Ed25519 cryptographic signature
verify_signaturesVerify Ed25519 signatures
verify_certificationVerify UTS authority certifications

Connect to Claude:

{
"mcpServers": {
"intenttext": {
"command": "node",
"args": ["./node_modules/@dotit/mcp/dist/index.js"]
}
}
}

Related: