@flashyos/backlog
v0.1.1
Published
backlog/1 — the future tense of a record. One item per intention, filed where the work happens, emitted as a fragment per repository and merged into one list across an estate or a portfolio. Filed is private, publication takes a named human, and every ite
Downloads
156
Maintainers
Readme
@flashyos/backlog
backlog/1 — the future tense of a record.
The Directory records what is true. The frontdoor records how to approach. A
settlement receipt records what was agreed. None of them can hold an
intention — so the actual backlog of an estate lives in seventeen TODO.md
files, a dozen issue trackers and several heads, and a partner network matches
on whatever somebody remembered to type into a form.
backlog/1 is one item per intention, filed where the work happens, emitted as
a fragment by the repository that owns it, and merged into one list across an
estate or a portfolio.
npm i @flashyos/backlogThree rules carry the design
Filed is not published. file() has no visibility parameter. An agent may
file anything and can publish nothing; promote() throws for any id that is not
a person/. Publication is recorded on the item — who, when, and optionally
why. This is agents suggest, humans consent as a type signature rather than a
paragraph in a contributing guide.
Every item decays. expires is derived from the kind and is refused as
input. A blocker is current for fourteen days, an idea for a hundred and eighty.
Nothing deletes an expired item — stale() finds them and summary().decay
reports the share of your live list that has quietly stopped claiming to be
true. A backlog that does not decay is a lie told at increasing volume.
Nobody files work onto somebody else. An item's owner belongs to the emitting organisation, and a fragment may only carry items whose ids name its own repository. Cross-organisation intent goes through the mesh, where the other side approves it — never as a row that appears in their list because a stranger wrote a file.
Use it
import { file, promote, merge, view, forOwner, summary, toRoadmapItem } from '@flashyos/backlog'
// An agent files, on the push that raised the question. Private, rev 1,
// expiry derived from `kind`.
const item = file({
id: 'backlog/flashyos/settlement-explorer',
kind: 'task',
title: 'Ship the settlement explorer',
source: { repo: 'repo/flashyos', ref: 'https://github.com/FlashyLabs/flashyos/pull/412' },
assertedBy: 'agent/flashyos-builder',
owner: 'person/michael',
capabilitiesWanted: ['settlement', 'audit'],
})
// A human publishes it — and only a human can.
const published = promote(item, { by: 'person/michael', to: 'partner', note: 'wanted for Q4' })
// Many repositories, one list.
const { backlog, problems } = merge([fragmentA, fragmentB, fragmentC])
forOwner(backlog.items, 'person/michael') // what is waiting on one node, everywhere
summary(backlog).decay // 0.41 — and now you know
toRoadmapItem(published) // the FlashyOS roadmap surfaceview(backlog, 'public' | 'partner' | 'private') filters the query, not the
render: nothing downstream ever holds a record it is not entitled to and then
remembers to hide it. A private item is indistinguishable from a missing one.
The command line
flashy-backlog check <file|dir> validate fragments; exit 1 on any error
flashy-backlog merge <file|dir> [--tier T] [--out F]
flashy-backlog summary <file|dir> the one-page read
flashy-backlog mine <node-id> <file|dir> what is waiting on one node, everywhere
flashy-backlog stale <file|dir> live items past their decay window
flashy-backlog seeking <file|dir> published asks the network can matchIt takes paths, not a base URL. A portfolio owner with eleven fragment files on a laptop gets the same answers the dashboard does, which is the point: the roll-up is a projection of published documents, not a view only we can render.
Adopt it in one command
npx @flashyos/backlog adoptReads the repository — its remote, its AAO charter if it has one, and which
directory it actually serves from — then writes .backlog/config.json, an
empty items list, the dependency-free emitter, and a workflow. It tells you
every decision it made and why.
Adopting publishes nothing. Items are filed private and reach the served
fragment only when a named human promotes one. The served copy is the public
projection and the emitter writes it — not a copy step in a workflow, because a
step can be forgotten and forgetting this one would publish private items at a
URL. partner is excluded from anything served without authentication: a
partner-tier item behind no gate is a public item with a misleading label.
| Repository shape | Where the public projection lands |
|---|---|
| Next app, or a static builder with a public/ | public/.well-known/backlog.json |
| Monorepo with a marketing app | apps/marketing/public/.well-known/backlog.json |
| Serves its dot-directory through a rewrite | well-known/backlog.json — and you add the rewrite |
| No site at all | nowhere; the fragment sits at the repository root and is merged from a checkout |
No toolchain? vendor-backlog.mjs
A single dependency-free ESM file. Copy it into any repository — including one
with no package.json — and it files, promotes, closes and emits a valid
fragment with node alone.
node vendor-backlog.mjs file --id ship-the-thing --kind task --title "Ship the thing"
node vendor-backlog.mjs promote ship-the-thing --by person/michael --to partner
node vendor-backlog.mjs emit # → backlog.fragment.jsonIt carries its own copy of the decay windows and the promotion check, and
src/vendor.test.ts asserts that copy matches this package. A vendored copy
that is merely similar is how a consent rule becomes advisory.
The loop it closes
file() ──▶ promote() ──▶ RoadmapItem ──▶ matcher ──▶ JointInitiative
▲ │
│ InitiativeTask
│ │
└──── closedBy() ◀──── settlement receipt ◀──── evidence ◀───────┘Six of those eight steps already existed in FlashyOS. This package is the two that did not: where the intention comes from, and where it goes when the work is done.
Licence
Apache-2.0. The spec and the clients are permissive on purpose — a standard nobody can embed is not a standard.
The version key — intent since 0.1.1
The format shipped as backlog/1 and became IntentMesh's intent/1. Since
0.1.1 (INTENT_KEY_SINCE) the emitter writes "intent": "1" — beside
"backlog": "1" for as long as a vendored copy of the checker somewhere in the
estate still requires the old key — and every reader here accepts either key,
forever. Item ids stay backlog/<repo>/<slug>: an identifier is not rewritten
when a format is renamed. See SPEC.md, "The version key".
