Coding agents read files: a rules document, skill
directories, a list of MCP servers. Those files live in every repo, in a
different dialect per harness, and they drift — silently, because nothing
checks them. Agent config moves the source
of those files into Flicker: one library per organization, assigned to the
projects that should have it, written out by flicker harness sync.
The files stay exactly where they are. What moves is their authorship — the lockfile model. Flicker never pushes to your repo; you run the sync and you commit the result.
Three kinds, three costs
Rules, skills, and MCP servers are not three flavours of the same thing. They differ in when the agent pays for them, and that is the whole basis for choosing between them.
Rules — always on, repo-scoped
Prose the agent reads on every turn. Rules project into one file, AGENTS.md, in the repo they are assigned to. Being always
loaded is the point and
the price: every rule costs context in
every session. Reach for a rule when something must be true of all
work in this repo — the object model, a naming convention,
a deploy gate.
Skills — on demand, and only the description is always loaded
A SKILL.md plus whatever files it needs. The harness keeps
every skill's description in context at all times and
fetches the body only when the agent decides to open it —
so a long skill is cheap and a bad description is fatal. Skills are not
repo-scoped in the harness's own model: a skill is a capability the
agent can reach for. Reach for one when the instructions are long and
only sometimes relevant — a migration procedure, a component-authoring
guide.
MCP servers — capability, not text
Not instructions at all: a specification of a process the harness
launches, which gives the agent tools. It costs nothing in the
description index. What it costs instead is that installing one is
multi-part
— the registration itself, plus whatever the
spec declares in requires[]: a binary on PATH
(bin:), a project dependency (dep:), a
plug/module wiring (plug:), an environment variable
(env:), a file (file:). Miss one part and the
server is quietly not there — which is why
doctor
reports every part by name.
The rule of thumb
Who owns it, and where it applies
Every assignment lands in one cell of a two-by-two grid: an owner (the organization, or you) crossed with an applies-to (everywhere, or one project).
| Everywhere | One project | |
|---|---|---|
| Org-owned | Org policy — every project, every member | The org's config for this one project |
| You-owned | Your config, in all your projects | Your config, in this project only |
There is no project-owned config
“Project” is the applies-to axis, never the owner axis. A project never owns an entry — an organization or a person does, and either can narrow what they own to one project. If you are looking for a third owner called “the project”, it does not exist, and the cell you actually want is org-owned, this project.
Precedence, in the order it is applied:
- Harness targeting filters first. An entry targeted at one harness is out of the running entirely when a different harness's projection is being rendered — so it can never shadow something that would have applied.
- Within one owner, narrower beats wider. That owner's project-scoped assignment beats their own org-wide one. An organization that adds a plain project-scoped row has, for that project, locally opted out of its own org-wide assignment — which is deliberate, and the same act as pinning a version there.
-
Across owners, yours wins — unless the org enforced theirs.
enforcedis org-only and it always wins. Style is personal; correctness is not.
Assigning org-wide and marking an assignment enforced are manager-only: one reaches every project and every member, and the other is specifically the power to override somebody's personal choice.
Library and assignment
The library is the content: registered skills, MCP specs, and rules — versioned, owned by the org or by a person. An assignment attaches one library entry to one cell of the grid. One entry can have many assignments; the content is stored once, however many places use it.
- Versions are append-only. There is no edit that overwrites. A change writes the next sequence number with a note and an author, and the entry's pointer moves; every earlier version is still there and still readable. There is no one-command revert — going back means publishing the old body as the next version, which keeps the record of both the mistake and the undo.
-
An entry with no description is a draft, and does not project.
A description is the only thing an agent reads before deciding
whether to open a skill, so an entry without one can never be routed
to; writing it to disk would put bytes there that nothing will ever
reach for. Write a description and publish the next version to
promote it, or say so outright with
flicker harness publish <name>. -
Retire rather than delete.
flicker harness deprecate <name>stops the projection while keeping the entry's assignments and its history. An entry that still has assignments cannot be deleted at all, because deleting it would silently change what agents read. -
Provenance is recorded on both halves.
An entry can carry where its content came from —
git+https:,npm:, orpath:— and every version records who wrote its description:upstreamas shipped,aiif a model wrote it,humanif a person did. Descriptions steer when a skill fires, so a rewrite has to stay visible after the fact.
In the web UI: Agent library is the org's entries with the version history behind each one; Agent policy (Settings → Agents) is the organization's owner layer and My agent rules (Settings → My agents) is yours; and a project's Agents tab is the effective view — precedence already applied, so a row that appears there is a row an agent gets. That tab may change exactly one cell, org × this project; every other row links to the page that owns it, because removing an org-wide entry “from this project” would either do nothing or change every other project.
The workflow
One command does the common case: publish the skill to the library, assign it to this project, and write it into every harness detected here.
$ flicker project use acme # binds this directory: writes project = "acme" to ./flicker.toml $ flicker harness install skill ./commit-style $ flicker harness doctor
The same thing in its separate steps, plus the rest of the surface:
$ flicker harness skill new commit-style # scaffold ./commit-style/SKILL.md $ flicker harness skill publish ./commit-style --pack house $ flicker harness assign commit-style --org-wide --enforced $ flicker harness assign commit-style --harness cc $ flicker harness list $ flicker harness sync $ flicker harness sync --check # CI probe: exit 0 fresh, exit 1 stale, writes nothing $ flicker harness unassign commit-style $ flicker harness export --out agent-config
Where a sync writes, per harness:
| Harness | Path |
|---|---|
| cc | .claude/skills/<name>/SKILL.md · MCP servers merged into .mcp.json |
| codex | .flicker-agent/agent-config/skills/… · an index block in AGENTS.md |
| pi | .pi/skills/<name>/SKILL.md |
| opencode | .opencode/skills/<name>/SKILL.md |
| rules | AGENTS.md — one file, read by every harness |
The Codex block is an index, not an inlining: a dozen skill
bodies pasted into AGENTS.md would load every one of them into
every session, which is exactly the cost the description budget exists to
control. And a kind a harness has no documented home for is reported as unprojected, never written to an invented
path — a rule dropped into a file nothing reads is worse than a rule you
were told was not projected.
Sync is a sync, not an append
.flicker-agent/harness/<name>.json. Un-assign
something and the next sync removes it. A file Flicker never wrote is
never a deletion candidate — a hand-written skill, or another tool's
skill, in the same directory is left alone.
Export is the removability guarantee.
flicker harness export writes the effective config as plain
files with no harness dialect and no Flicker metadata. If you ever want
out, that directory is what you keep.
AGENTS.md becomes a generated artifact
Prose rules are library entries like anything else, but they project
into one
file rather than a per-harness directory, because AGENTS.md
is what every harness, every CI job, and every
collaborator who has never heard of Flicker actually reads. The file
stays; its authorship moves.
$ flicker harness import # registers each section of AGENTS.md as a rule, hands the file back generated $ flicker harness rule add acme.review ./review.md $ flicker harness sync # re-renders AGENTS.md; you commit the result
import
is the migration, and it is the only
thing that adopts a file. It reads the existing AGENTS.md, registers each section as a rule
(project-qualified, so thirteen repos' “## Object model”
sections cannot collide), and hands the file back generated. From then
on sync
re-renders it — but only because the file is already
Flicker's. A repo that never imported keeps its hand-written AGENTS.md
untouched and gets the generated document at
.flicker-agent/agent-config/AGENTS.md
instead, which is what --overlay
makes permanent for a repo that may not commit
generated files.
import
ingests the human's
document: any block Flicker
already manages in that file is dropped before parsing, so its own
output is never registered back as a rule — and the blocks belonging to
flicker skill install
and to the Codex skill index are
preserved through adoption rather than silently uninstalled. Everything
before the first ##
becomes a section too, and the parser is
fence-aware, so a ##
inside a code block stays content.
Rendering is deterministic: same rules in,
byte-identical file out, with no clock and no incidental ordering. That
is not a nicety — drift detection, sync --check, and the
promise that a re-sync is a no-op are all “compare the bytes on
disk to the bytes the renderer produces”.
The generated document puts the project's
own rules first and
verbatim, then the organization's under an ## Organization rules
heading with enforced ones labelled.
Org rules are the appendix rather than the preamble for a structural
reason: a section introduced by an H2 and followed by the repo's own
headings would visually swallow them, and a section at the end cannot
capture anything after it.
Edit the rules, not the file
sync puts the generated bytes back. Move
the edit into a rule instead. Two writes refuse outright rather than
proceeding: one that would leave the target empty, and one that would
render project B's rules over project A's AGENTS.md.
Personal rules are never committed.
A user-owned rule renders only into .flicker-agent/local/AGENTS.md, which ships next to a
.gitignore
that excludes it. There is no code path that can
hand a personal rule to the writer that touches the committed file.
doctor: what is actually on disk
Every other verb reports intent — what the library says should
be true. flicker harness doctor reads the disk. It also
reports the parts that are fine, because
“nothing is wrong” and “nobody checked”
printing the same output is how this class of problem stays invisible.
- drift (hard) — declared bytes versus actual bytes, per harness: files missing, files whose content was edited, and files still present that are no longer assigned.
- mcp (hard for the registration, warning for prerequisites) — every part of the multi-part install, by name, and in both directions: a server that never got registered, and one Flicker registered that is no longer assigned yet is still launched — an executable with tool access — by every session in the project. Machine-local parts are named with the machine they are missing on, so “works on mine” becomes a checkable claim.
- scope (hard) — an entry the library marks project-only that is assigned org-wide.
- budget (warning, always with the real numbers) — the description index, counted across every user-scope skill read path, deduped by resolved path. Watching one directory of two once reported a machine healthy while its index was four times over.
Drift and scope are hard findings and exit 1.
Prerequisites and budget are warnings and exit 0: they are
facts about a machine, not drift in the config Flicker owns.
The description budget, and what going over really does
A harness loads every skill's description into every session. Past roughly 3,000 tokens of descriptions in one scope, the harness silently strips them — and a skill with no description can never be routed to. It does not become quieter; it becomes unreachable, while still occupying disk and still appearing in every listing. Nothing tells you.
So Flicker measures it and blocks nothing.
Budget is a warning, never a gate.
The number is a fact about a machine's read paths rather than about
your config, and a refusal in the middle of a sync would leave a worse
state than the one it prevented. Where the numbers appear: skill publish
prints the new entry's own description cost against the budget; harness list
and harness doctor
print the scope total with the per-entry breakdown; and harness sync
warns after writing when the scope it just wrote is over. harness assign
does not print them — run harness list
after assigning.
Two credentials, and why the difference matters
An org API key (flk_) acts as the
organization. Mint it under your org's Settings → API Keys. It is what CI uses, what deploys,
what reads secrets — everything except personal agent config.
A personal CLI token
(flk_usr_) acts as you, inside one organization. Mint it under Account Settings → CLI tokens. It is the only
credential that carries an identity, which is what makes user-owned
config possible at all: the credential decides the owner, and
nothing on the wire does.
Without --personal
the org key
is used and the config is the org's; with it, the personal token is used
and the config is yours — invisible to the org key and to every other
member. Sending the wrong credential cannot produce the wrong owner,
only a 403.
$ flicker auth login flk_live_xxx # org resolved from the key, stored, made current $ flicker auth user flk_usr_xxx # stored alongside the org key for that org $ flicker auth list $ flicker harness install skill ./mine --personal $ flicker harness sync --personal # org config PLUS your own; enforced org config still wins
A personal token is deliberately near-powerless: it may reach GET /whoami
and the /agent-config/*
routes and
nothing else. It cannot deploy, read a secret, send mail, or touch a
database. That list is what it can
do rather than what it cannot,
so a route added tomorrow is closed to it until someone decides
otherwise — which is what makes it safe to keep in a plaintext file on a
laptop.
Never authenticate CI with a personal token
flk_usr_
gets 403
on every
deploy, database, environment, and secrets route — the deploy fails, and
it fails at the API rather than at login. CI wants FLICKER_TOKEN
set to an org
API key. FLICKER_USER_TOKEN
is the personal token's CI form, and an
org key is never substituted for it.
Both credentials are stored per organization, so flicker auth list
shows every org this machine holds either
for, and the personal token is used only for the current
org. If
yours belongs to another org, select it with flicker org set <slug>
or --org <slug>. Storing a personal token also makes
its org current when none is selected yet, so a member with no org API
key at all can use --personal
immediately.
Revoking. Account Settings → CLI tokens lists every token you hold with its prefix, its organization, and when it was last used; Revoke stops it immediately, on every machine holding it. Tokens are minted without an expiry, so revocation is the recovery path for a laptop you no longer control. Membership is re-checked on every request as well — a token stops working the moment you leave the organization, however long ago it was minted.
What is verified, and what is not
Stated plainly, because a docs page that overclaims here costs someone a day.
- Claude Code is the harness verified end to end — published in Flicker, synced to disk, and picked up by a live session. The Codex, Pi, and opencode adapters write to each harness's documented path (opencode's was read out of the shipped binary's own documentation), but model pickup has not been verified live for any of the three. Treat them as “written where the docs say”, not as “proven to load”.
-
MCP entries are created in the web UI or the API, not the CLI.
flicker harnesshas verbs for skills and rules; an MCP spec is registered on the Agent library page, its body being the server object the harness expects. The CLI syncs and diagnoses MCP entries, and only Claude Code has a projection for them today — for the other three harnesses they are reported as unprojected. - An assignment follows its entry's latest version. Pinning an assignment to a specific version exists in the data model and the UI shows a pinned row as pinned, but there is no CLI flag or UI control that sets it.
-
Prerequisites are recorded, not enforced.
An MCP spec's
requires[]is stored and checked by doctor; nothing gates a projection on it. - The budget is advisory. Nothing refuses a write because a scope is over it.