← the whole session plugin/skills/intent-db/SKILL.md

Query or record confirmed UX decisions in a local Intent DB. Use for READ (\"what should happen when X\", \"what's the intended UX\", \"check the intent db\") or WRITE (\"log intent\", \"document intent\", \"record why we built X\", \"add to intent db\", \"propose intent\").

Intent DB

A record of confirmed decisions about how the product should behave for the people using it — a small hierarchical store of statements, each one traceable back to why it exists. Agents should query this FIRST when making decisions about UX, feature behavior, or implementation patterns, instead of guessing from the code and treating the guess as settled.

This ships as a local file store (intent.js, next to this skill) — one JSON file per entry, no database or server required. If you already run a database-backed intent store of your own, you can point intent.js's resolveStoreDir() at it instead; the local file store is the default so this works on day one with nothing else installed.

Quick Start for Agents

1. Search before building

node <path-to-this-skill>/intent.js find "premium feature"
node <path-to-this-skill>/intent.js find "session expiry"

2. Check canonical decisions

Canonical intents are the source of truth — settled decisions the person has confirmed matter enough to outrank everything else. They appear first in search results.

node <path-to-this-skill>/intent.js canonical

3. Get recent decisions

node <path-to-this-skill>/intent.js recent 10

If the store is empty or nearly empty, that's expected on day one — say so plainly ("nothing confirmed on this yet, proceeding on my own best judgment") rather than presenting silence as an answer either way.


CLI Reference

# Search (only returns approved entries)
node intent.js find <query>

# Get a specific intent
node intent.js get <slug>

# Hierarchy
node intent.js children <slug>
node intent.js tree <slug>

# Recency and priority
node intent.js recent [n]
node intent.js canonical

# Refresh timestamp (boost in search when you re-confirm something still holds)
node intent.js touch <slug>

# Propose a new entry — starts as status: proposed, invisible to search until approved
node intent.js create '<json>'

# Approve a proposed entry so it becomes something agents can treat as settled
node intent.js approve <slug>

# Compact ~500-token summary for briefing a sub-agent
node intent.js brief <slug>

node intent.js with no arguments prints the same reference plus where the store lives on this machine.


The proposed/approved split — this is the mechanism, not decoration

An agent's guess about intended behavior is not the same thing as a confirmed decision. When no entry exists for something you need to know:

  1. Search first (find). If nothing turns up, say so out loud.
  2. Write your best-guess answer as a create with status: proposed (the default) — this records the guess as a guess, not as settled fact.
  3. Only entries with status: approved come back in find/recent/canonical/tree/children. A proposed entry stays invisible to future searches until a human reviews and runs approve on it.
  4. Never treat your own proposed entry as though it were already confirmed — that's exactly the "guessing, then presenting the guess as settled reality" failure this mechanism exists to prevent.

Briefing sub-agents from the same entry

The brief command shrinks one entry down to its core rules, a "never do" list, and its when/then promises (~500 tokens) — hand that to each helper you dispatch so they aren't guessing independently of each other.

Citing intent in changes

When proposing or committing a change that a confirmed intent bears on, cite it — the slug, which rule, and how the change relates (supports, implements, extends, questions, or deprecates the intent). If you have a proposal-tracking system, put the citation there; otherwise say it plainly in the commit message. This is what lets someone later see why a piece of code exists, not just what it does.


Schema reference

{
  slug: String,           // required, unique (e.g., "onboarding.first-run-empty-state")
  title: String,          // required
  primaryIntent: String,  // required - the core "what" statement, in UX-centric form (see below)
  tags: [String],         // include 'canonical' for a settled, source-of-truth decision

  // Hierarchy
  parentSlug: String,     // for nesting under a broader intent
  depth: Number,          // 0=root, 1=child
  order: Number,          // sort among siblings

  // Content
  items: [{
    statement: String,    // the intent statement
    therefore: [String],  // what this means in practice
    why: [String],        // rationale
    notes: [String],      // edge cases, UX characteristics
  }],

  // UX Contracts
  uxPromises: [{
    when: String,          // trigger condition
    then: String,          // expected outcome
  }],

  stack: [String],        // visual summary bullets

  // Workflow
  status: String,         // proposed | approved
  proposedBy: String,
  approvedAt: String,     // ISO date

  createdAt: String,      // ISO date, auto-set
  updatedAt: String,      // ISO date, sorted by this for "recent"
}

Writing intents: UX-centric format (required)

Intents are about the USER'S EXPERIENCE, not code behavior.

When writing or proposing intents, describe:

  1. WHEN — the user's state or trigger.
  2. WE AIM TO — what we render or show the user.
  3. HOW — how we determine what to show.
  4. BECAUSE — why this serves them (their journey toward whatever "working" means for your product — that might be an aha-moment-to-conversion-to-retention funnel for a consumer product, or something else entirely for a different kind of product; write the version that's true for yours).

❌ BAD: Code-Centric (rejected)

The intent of this function is to check feature flags and render components based on conditions.
This component's intent is to query the user's subscription status and display appropriate UI.

These describe CODE, not USER EXPERIENCE.

✅ GOOD: UX-Centric (required)

Example from a real product (opt-in — replace with your own domain and journey):

When the user lands on the home screen, the first thing we aim to render is a prediction of the
optimal next step for that user. We work that out by checking which features they've already
adopted and where they are in the signup funnel — not logged in, mid-trial, and so on.

We aim to render the single most likely useful next step for them, based on what will move them
toward their next meaningful outcome — and if they haven't converted yet, toward that decision;
if they have, toward the next thing that keeps them getting value long-term.

Notice:

  • Written from the USER's perspective ("when the user lands...").
  • Describes what we AIM to show, not what the code does.
  • Explains WHY in terms of the user's own journey — for your product, substitute your product's own idea of "working."
  • Conversational and human-readable.

Intent writing checklist

Before submitting an intent, verify:

  • Does it start with "When the user..." or similar user-centric trigger?
  • Does it describe what we AIM TO render/show, not what the code does?
  • Does it explain WHY in terms of what actually matters to the person using the product?
  • Could a non-technical person understand the user experience from reading it?
  • Does it avoid code terminology (functions, components, queries, APIs)?

When to query the Intent DB

Check it when:

  • Implementing any feature involving a paid tier, trial, or subscription state.
  • Building gated or premium features.
  • Handling authentication states.
  • Making UX decisions about modals, redirects, or messaging.
  • You're unsure about intended behavior and don't want to guess silently.

The pattern:

  1. Search for relevant entries.
  2. Read the canonical entry if one exists — it outranks everything else.
  3. Cite it in your proposal/commit.
  4. If nothing exists, propose one (status: proposed) rather than building on an unstated assumption.

Seeding an empty store

A brand-new store is empty, and that's expected — it grows only from confirmed decisions going forward. To get a running start instead of building it one conversation at a time: read this project's own CLAUDE.md, READMEs, or design docs, and your own past Claude Code sessions (~/.claude/projects/*/*.jsonl, see the agentic-find skill's local fallback) for statements of what you were told to build and corrections you received — those are often the clearest record of confirmed intent that already exists but was never written down here. Draft entries from what you find as proposed, quote rather than paraphrase where you can, and have the person approve each one rather than bulk-approving.