How skills work
A skill is how you give the agent a rule it actually reads at the moment it matters — your code-review checklist, your “never force-push main” discipline — instead of burying it in a system prompt it agreed to and then ignored two turns later. The gateway hands the agent the rule when it’s about to act, not at the top of a context window that’s since filled up.
The conceptual story lives in Skills, workflows, and cognitive architectures — what a skill IS, why the three-layer model matters, when you’d reach for one. This page is the operational rundown: where skills live, how they load, how the gateway surfaces them, and how an in-flight workflow keeps seeing a stable copy.
Anatomy
Section titled “Anatomy”A skill is four fields under a subject key:
skills: review.code.adversarial: verb: review lifecycle: stable body: | # Adversarial patch review
Attack the candidate patch: missed edge cases, hidden regressions, policy violations, security issues. Cite each finding with file:line and a counterexample. Return verdict: accept | retry | escalate.| Field | Required | What it does |
|---|---|---|
verb | yes | One of the 10 cognitive verbs (reference). Closed enum. |
lifecycle | yes | experimental | stable | deprecated. Governs the deprecation conventions you ship under. |
body | yes | The Markdown guidance the model reads. Aim for 100–400 words; one mental model per skill. |
source | no | Where the skill came from (config, ingest, repo provenance). Auto-set by ingest paths; manual entries default to config. |
hash | no | If present, must equal sha256(normalize_for_hash(body)). Hash drift is HASH_MISMATCH at load. |
You name a skill by giving it a verb and a dotted subject like review.code.adversarial — what it does (review) and what it’s about (code.adversarial). That’s the whole mental model; the rest is validation that keeps names consistent across a growing library.
The subject is the key — review.code.adversarial above. At least two segments, lowercase kebab. The first segment must be one of a fixed set of subject roots; under strict namespacing (default), an unrecognized root fails load with INVALID_SUBJECT_ROOT. See Cognitive verbs for the full root list and the reasoning behind the closed set.
Where skills live
Section titled “Where skills live”Two places, and they compose.
Inline in the gateway config
Section titled “Inline in the gateway config”version: "1.0.0"
skills: review.code.adversarial: verb: review lifecycle: stable body: | # Adversarial patch review ...This is the simplest path. One file, no repo manifest, you ship and own the skill yourself. Good for skills that are highly specific to your codebase or your team’s vocabulary.
From a repo’s skills/ directory
Section titled “From a repo’s skills/ directory”A resource repo with a flowgate.repo.yaml manifest can ship a skills/ directory whose *.yaml files load into the gateway’s skills registry. Each loaded subject is namespace-prefixed <repo-namespace>/<subject>:
schema: flowgate.repo/v1name: cognitive-architecturesnamespace: cognitiveversion: 0.6.0layout: skills: skills # ← skills/*.yaml load from hereskills: review.code.adversarial: verb: review lifecycle: stable body: | # Adversarial patch review ...When the operator wires this repo into their gateway config…
version: "1.0.0"repos: - path: ~/repos/cognitive-architectures…the skill lands in the registry under cognitive/review.code.adversarial. Two repos can ship skills with the same bare subject without colliding — the namespace prefix disambiguates.
See Multi-repo loading for the full repo loading semantics. Both inline and repo-loaded skills compose into the same registry; you can have one repo provide review.code.adversarial and another provide review.code.style-only and your gateway sees both.
How a workflow surfaces them
Section titled “How a workflow surfaces them”A workflow names the skills it wants surfaced:
workflows: review-pipeline: initialState: critiquing skills: [review.code.adversarial, review.code.final-approval] states: critiquing: skills: [review.code.adversarial] # state-scoped surfacing transitions: { ... }skills: can sit at three scopes:
| Scope | Surfaces to | When you’d use it |
|---|---|---|
| Workflow-level | Every state in the workflow | ”This whole workflow is review work; every state benefits from the rubric.” |
| State-level | Just that state | ”The critiquing state needs the adversarial rubric; the next state doesn’t.” |
| Transition-level | Just when that transition is the current decision | ”Only when the model is about to fire escalate, surface the escalation rubric.” |
The model gets the subjects (the menu), not the bodies (the meal). When it decides a particular skill is relevant, it calls flowgate.query({subject}) to fetch the body — it pulls one rule at a time, only when it’s about to use it. That’s what keeps the agent from carrying a wall of guidance it skims and forgets.
Cross-namespace references from repo-loaded workflows
Section titled “Cross-namespace references from repo-loaded workflows”A workflow loaded from a repo references skills by bare subject. The runtime resolves them against:
- The workflow’s own namespace prefix first —
cognitive/review.code.adversarial. - Then the bare subject —
review.code.adversarial.
So a workflow shipped by cognitive-architectures writes skills: [review.code.adversarial] and lands the namespaced version automatically. To reference a skill from a different namespace, fully qualify it: skills: [internal/review.compliance.strict].
The lookup is the same fall-through pattern Multi-repo loading describes for kind: workflow references.
How the model finds them
Section titled “How the model finds them”The two MCP tools are how the model discovers and reads skills:
flowgate.query with query searches them
Section titled “flowgate.query with query searches them”The search index includes every loaded skill alongside capabilities and workflows. Each skill contributes its subject, verb, source, and body to the index. A query like "adversarial review" ranks review.code.adversarial highly because the term hits the subject + verb + body together.
The model can filter by kind (flowgate.query({ query: "review", kind: "skill" })). Closed-enum verbs make the filter deterministic — no fuzzy matching across “review” vs “evaluate” vs “critique.”
flowgate.query with subject returns the body
Section titled “flowgate.query with subject returns the body”{ "name": "flowgate.query", "arguments": { "subject": "cognitive/review.code.adversarial" }}returns the verb, body, hash, and source. The model reads the body, applies the guidance, and acts. The describe call is what the workflow’s skills: ref anticipates the model making — you list the subjects the workflow expects the model to need; the model fetches each body once when it actually decides it needs it.
Edit a skill mid-run and the in-flight workflow keeps the old version
Section titled “Edit a skill mid-run and the in-flight workflow keeps the old version”Edit a skill while a workflow is running, and the in-flight instance keeps the version it started with — no half-applied rule changes, no two states in the same run grading against different rubrics. Fresh instances pick up your edit; the ones already moving finish on the rules they began with.
The mechanism: when a workflow instance is created, the runtime freezes a copy of every skill the workflow references — body, hash, and verb — onto that instance. It carries that copy for its whole lifetime; later get and submit calls read from the frozen copy, never from the live skills: config.
What that buys you:
- Mid-flight edits don’t leak. Hot-reload the config with an updated
review.code.adversarialbody, and in-flight review pipelines keep the original until they terminate. No flicker, no half-evaluated workflows. - Hot-reload safety. A SIGHUP config reload (
config.reloadedaudit event) swaps the live registry atomically. Instances mid-transition are unaffected. - Reproducibility. Replay a workflow’s audit log a year later and the frozen copy tells you exactly what guidance the model was looking at — even if the skill body in your repo has changed since.
Hash drift detection
Section titled “Hash drift detection”If a skill ships with an explicit hash: field, the runtime computes sha256(normalize_for_hash(body)) at load and refuses to start if they don’t match. Useful when:
- You vendor a skill from another repo and want to assert it hasn’t drifted (you ship the body + a hash you generated; the load fails loudly if either changes without the other).
- A skill body is being edited collaboratively and you want CI to catch desync between the body and a manifest that references its hash.
The normalization (whitespace collapse, trailing-newline trim) is stable across releases. Read-side and write-side parity is enforced by cross-impl test.
The guidance_acknowledged guard pattern
Section titled “The guidance_acknowledged guard pattern”A capability or transition can require the model to have fetched a skill body before firing:
states: about_to_review: transitions: submit_verdict: target: done guards: - kind: guidance_acknowledged subject: review.code.adversarialThis passes only if the model called flowgate.query({subject: "review.code.adversarial", workflowId: "..."}) on this workflow AND the recorded body hash matches the current snapshot’s hash. Hash flip → acknowledgment expires → the model has to re-read.
Use this when the guidance is load-bearing — when you want the runtime to enforce “you read the rubric before you submitted the verdict.” Don’t sprinkle it on every transition; it adds friction. Reach for it on the transitions where skipping the rubric would cost something real.
How airtight that enforcement is depends on how you run flowgate — inside Claude Code or Cursor it gates everything routed through it; run the loop in flowgate’s own TUI and the guard is absolute. How to run it lays out the modes.
Authoring discipline
Section titled “Authoring discipline”Some practical conventions that emerge from real use:
- One mental model per skill. If you find yourself writing
# Section 1,# Section 2headings, split. The model loads skills one at a time; each one should be the smallest coherent thing it could think about. - 100–400 words. Long enough to encode actual discipline; short enough that the body cost isn’t a tax on every snapshot-stamped instance.
- Cite the trap. Skill bodies are at their best when they name a specific failure mode. “The temptation here is to…” or “Anti-pattern:” lines do more for model behavior than abstract principles.
- Bounded scope.
review.code.adversarialis good.review.code.everything-you-need-to-knowis too broad — split into the actual sub-disciplines. - Lifecycle honestly. Mark experimental skills
experimental— operators see this inflowgate.query({subject})describe responses and treat them accordingly. Promoting tostableis a commitment.
What’s next
Section titled “What’s next”- Skills, workflows, and cognitive architectures — the conceptual layered model.
- Cognitive verbs — the 10-verb cloud and blessed subject roots.
- How scripts work — the deterministic peer to skills.
- How everything composes — the full repo author tour.