One library of rules, skills, and MCP servers — assigned per project, written into every harness

Agent config

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

If the agent needs it every time, it is a rule. If it needs it sometimes and it is long, it is a skill. If it needs to do something rather than know something, it is an MCP server.

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
i

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. enforced is 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:, or path: — and every version records who wrote its description: upstream as shipped, ai if a model wrote it, human if 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.

publish + assign + sync
$ 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:

the longhand
$ 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.

i

Sync is a sync, not an append

Each harness gets a manifest of exactly what Flicker wrote, at .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.

adopt an existing AGENTS.md, then edit rules instead of the file
$ 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

A hand edit inside the generated block is reported distinctly from ordinary staleness — one of those is somebody's work about to be overwritten — and 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.

!
The estimate is descriptions-only and roughly four characters per token. It is advisory: treat a number near the limit as a reason to tighten descriptions, not as a measurement to tune against.

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.

store both; the token is shown once
$ 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

A build running as 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 harness has 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.