Skip to content

Write tools

Write tools capture friction events as agents work. Every call is fire-and-forget — the agent is never blocked. Events are buffered locally and flushed to reason.oka.so in the background.

observe

Record a general-purpose observation. This is the most flexible write tool — use it for anything that doesn’t fit neatly into the other categories.

observe(content, category?, tags?, workspace?)
ParamTypeRequiredDescription
contentstringyesWhat you observed
categorystringnoOne of: architecture, bug, convention, performance, security, workflow, dependency, code_quality
tagsstring[]noFree-form tags for filtering
workspacestringnoProject/repo identifier (defaults to cwd)

When to use: Architecture patterns you notice, performance characteristics, security considerations, workflow friction — anything worth remembering.

"The auth middleware silently drops requests when the JWT refresh token
expires during a concurrent request. This only manifests under load."

decision

Capture a choice with its rationale and the alternatives considered.

decision(decision, rationale, alternatives?, confidence?, tags?, workspace?)
ParamTypeRequiredDescription
decisionstringyesWhat was decided
rationalestringyesWhy this was chosen
alternativesstringnoWhat else was considered
confidencenumberno0.0–1.0, how confident in this choice
tagsstring[]noFree-form tags
workspacestringnoProject/repo identifier

When to use: Architectural choices, library selections, API design decisions, approach changes — any choice where the “why” matters.

decision: "Using pgvector for semantic search instead of a dedicated vector DB"
rationale: "Keeps the stack simple — one Postgres instance handles both
relational and vector queries. At our scale (<1M embeddings) the
performance difference is negligible."
alternatives: "Pinecone, Qdrant, Weaviate"
confidence: 0.85

explore

Record findings from exploration — investigating a codebase area, testing an approach, or researching a solution.

explore(content, area?, relevance?, tags?, workspace?)
ParamTypeRequiredDescription
contentstringyesWhat you found
areastringnoArea explored (e.g., “auth”, “billing”)
relevancenumberno0.0–1.0, how relevant to current work
tagsstring[]noFree-form tags
workspacestringnoProject/repo identifier

When to use: When an agent investigates a module, reads documentation, or tests an approach and discovers something worth recording.

"The Stripe webhook handler in billing/webhooks.ts silently drops events
when the signature verification fails — no error log, no metric. Found
while investigating why subscription renewals were inconsistent."

deviation

Note where reality diverged from the plan — a workaround, an unexpected constraint, or a course correction.

deviation(content, expected?, actual?, impact?, tags?, workspace?)
ParamTypeRequiredDescription
contentstringyesWhat happened
expectedstringnoWhat was planned
actualstringnoWhat actually happened
impactstringnoConsequence of the deviation
tagsstring[]noFree-form tags
workspacestringnoProject/repo identifier

When to use: Workarounds, plan changes, unexpected constraints. Deviations are high-signal events — they reveal where assumptions break.

content: "Had to use REST instead of gRPC for the internal gateway"
expected: "gRPC between services per ADR-015"
actual: "Cloudflare Workers don't support gRPC — used REST with protobuf serialization"
impact: "No streaming; polling required for long-running operations"

done

Mark a task or goal as complete, with outcome and quality signals.

done(task, outcome?, quality?, tags?, workspace?)
ParamTypeRequiredDescription
taskstringyesWhat was completed
outcomestringnosuccess, partial, or failed
qualitystringnoFree-form quality note
tagsstring[]noFree-form tags
workspacestringnoProject/repo identifier

When to use: At natural completion points — a feature shipped, a bug fixed, a migration run. The outcome signal helps consolidation distinguish successful approaches from dead ends.

task: "Migrated auth middleware from express to Hono"
outcome: "success"
quality: "All 47 tests passing, latency dropped from 12ms to 3ms"

learning

Distill an insight worth remembering across sessions. Use this for conclusions, not raw observations — the kind of thing you’d tell a teammate joining the project.

learning(content, tags?, workspace?)
ParamTypeRequiredDescription
contentstringyesThe insight
tagsstring[]noFree-form tags
workspacestringnoProject/repo identifier

When to use: When you’ve synthesized something from experience — not a single observation, but a conclusion from multiple data points.

"The billing service is the most common source of downstream blockers.
Three different agents this week worked around missing webhook retry
logic independently. This should be the next infrastructure priority."

feedback

Report whether a learning was useful during your work session. This feeds the learning-to-rank model that improves future context results.

feedback(learning_id, useful, reason?)
ParamTypeRequiredDescription
learning_idstringyesUUID of the learning
usefulbooleanyesWas it helpful?
reasonstringnoWhy it was or wasn’t useful

When to use: After context or learnings returns results and you’ve had a chance to evaluate them. Even a simple useful: true improves ranking for future queries.

Best practices

  1. Write often, write small. Five focused observations beat one giant brain dump. Consolidation handles synthesis.

  2. Use the right tool. decision with rationale is far more valuable than observe("decided to use X") — the structured fields make consolidation smarter.

  3. Include tags. Tags like auth, billing, ci make context queries precise. Without tags, consolidation relies solely on content analysis.

  4. Don’t worry about duplicates. Consolidation resolves contradictions and merges reinforcing signals. Recording the same insight twice with slightly different framing actually increases confidence.

  5. Record failures. A deviation or done(outcome: "failed") is more valuable than a success — it prevents the next agent from repeating the same dead end.