The default configuration repo for gm -- and the reference implementation of the gm spec for workflows-in-skills.
Every artifact under prose/, gates/, residual/, fsm/ and hooks/ is edited
here directly. rs-plugkit pulls from this repo at runtime (crate::config::resolve,
re-checked on the debounce below) -- nothing generates this repo's content from a
build, and no CI job overwrites a hand edit.
rs-plugkit still ships each of these as a compiled-in Rust default, used only when this repo (or whatever repo a project points at instead, see below) is genuinely unreachable -- offline, first dispatch before any cache exists, a transient network outage. That compiled default is an emergency fallback, not this repo's source: a change here reaches every project pulling from it the next time their local cache refreshes, with no rs-plugkit rebuild, no release, no cascade.
| Artifact | Read by |
|---|---|
prose/*.md |
crate::prose::resolve, via the instructions.dir key in gm.config.json below. |
gates/*.md |
The same prose::resolve, via messages.gates_dir. |
residual/*.md |
The same prose::resolve, via messages.residual_dir. |
fsm/graph.json |
crate::orchestrator::fsm::graph, via the fsm.graph key. |
fsm/predicates.md |
Reference only, generated by rs-plugkit's fsm-vendor verb from the compiled predicate registry -- not read back by resolution, kept here so a graph author can see which predicate names a gates.predicate field may use. |
hooks/*.js |
crate::orchestrator::transitions::run_hook, via the fsm.hooks_dir key, only when a graph edge names one in its hook field. |
No configuration needed. Every gm project consults this exact repo by
default -- crate::config::resolve()'s ImplicitDefaultRepo tier clones it
into .gm/config-source-cache-default and re-checks it on a debounce (a cheap
remote-ref probe, a fetch only when the sha actually moved; offline, the last
good local copy is used) with no file to write, no opt-in step. A hand edit
here reaches every project on their next debounce window.
To point at a different repo instead -- a fork, an org-private variant --
write .gm/config.source.json in the project (project-wide) or under your
home directory (user-wide):
{ "repo": "https://github.com/AnEntrypoint/gm-config", "reference": "main", "path": "" }This explicit spec outranks the implicit default above and clones into
.gm/config-source-cache instead (a distinct cache directory from the
implicit tier's, so the two never collide even if a project switches between
them across sessions).
Three separate resolution chains then read the cache. Each is per-key, and each falls through to the compiled default, so overriding one key leaves every other key on its default.
Prose, gate text and residual text (prose::resolve), first non-empty wins:
.gm/instructions/<key>.mdin the project.<cache>/<instructions.dir>/<key>.md--instructions.dirisprosehere.- The compiled default.
The FSM graph (fsm::graph), first usable wins:
.gm/instructions/fsm/graph.jsonin the project.<cache>/<fsm.graph>-- note this pointer is relative to the cache root, not toinstructions.dir, which is whyfsm/sits at the top level here.- The compiled default.
A vendored graph replaces the default wholesale; there is no merge. A tier that parses but fails validation is reported and the compiled default serves, so a broken graph is never quietly replaced by a different author's working one.
Config values (gm.config.json) resolve through four tiers: project-vendored
.gm/gm.config.json, the in-project repo spec, the user-wide repo spec, then the
built-in defaults.
Gate hooks execute from either the project-vendored tier or this config-repo tier.
A hook sourced from a config repo runs with the same authority as a project's own
local git history, including code execution -- point config.source.json only at
a repo you trust with that level of access. Hooks are refused only from the
compiled-default tier, which never legitimately carries one.
| Path | Controls |
|---|---|
prose/*.md |
The instruction text served per FSM state. entry is served every turn, every phase. |
fsm/graph.json |
The whole state machine: states, edges, the gates guarding each transition, and policy. |
fsm/predicates.md |
Generated reference of the gate predicates a graph may name. |
gates/*.md, residual/*.md |
Operator-editable denial and residual-scan message text. |
hooks/*.js |
Jit gate hooks, for conditions no compiled predicate covers. |
gm.config.json |
Index budgets, RAG/embedding settings, BM25+vector scoring, vector table/index names, pipeline budgets, instruction-payload shape, browser-witness extensions, discipline-note limits, claim-audit markers, cache budgets, sync debounce, the memory-md sync pass budgets (memory_sync), the opt-in TencentDB-Agent-Memory-compatible backend (memory.tencentdb_backend: enabled flag, data dir, embedding dimension, namespace routing). |
A genuinely different workflow -- different phases, different order, different
gates -- is established by replacing fsm/graph.json and the matching prose.
No Rust changes, no rebuild. Fork this repo to run your own defaults; edit the
fork directly and point .gm/config.source.json at it, per "How gm consumes
this repo" above -- forking is the only reason to diverge, since this copy is
never overwritten from anywhere else.
Each phase's "Preferences (named, narrow)" section in prose/*.md catalogues
the named techniques, principles and authors that scope that phase's judgment
calls. The catalogues were substantially expanded from
AnEntrypoint/engage's SKILL.md
Unified Anchor Workflow, a ~150-technique-across-8-phases reference graph.
The expansion folded engage's named anchors into gm's existing 9-phase
SPECIFY -> PROVE -> EMIT -> STATE -> CONC -> SEC -> RES -> DECIDE -> COMPLETE
FSM as an enrichment of each phase's own preferences list, rather than
adopting engage's control-flow graph (its own phase set, gate shape and
loop-back edges) wholesale. Reason: gm's gates and predicates
(mutables-all-resolved, no-synthetic-test-files, idempotent-dispatch-replay-safe,
and the rest) are compiled Rust, evaluated against this exact 9-state shape --
swapping in a different graph wholesale would break that wiring rather than
extend it. A project wanting engage's actual control-flow graph instead of gm's
can still do so by replacing fsm/graph.json per "What is configurable" above;
this repo's own default stays on gm's proven 9-phase shape with the enriched
catalogues.
A dropped placeholder. Several defaults carry {token} placeholders that the
caller substitutes after resolution: {gap_ms} and {threshold_ms} in
gates/long-gap-no-instruction.md, {modified} and {untracked} in
residual/dirty-tree.md. An override that hardcodes a value where a token belongs
still renders, just with a number that no longer tracks the policy it claims to
report.
An unknown predicate. gates.predicate may only name a predicate listed in
fsm/predicates.md, which is generated from the same registry the code dispatches
on. An unknown name produces a gate that can never be satisfied -- gm emits
fsm_unknown_predicate rather than failing silently, but the graph is still wrong.
For a condition with no compiled predicate, use a jit hook instead.
prose::resolve builds its config-repo path from gm.config.json: a key matching
the gates/ or residual/ prefix resolves against messages.gates_dir or
messages.residual_dir if declared (both point at the top-level gates/ and
residual/ directories in this repo), falling back to instructions.dir only for
keys outside those two namespaces. Every family -- prose, gates, residual, the FSM
graph -- is reachable from this repo as a config source, matching what this repo's
own directory layout implies.