Plan #
What vibescrobble has built and what it is building. One file per epic. milestones.md is the other view of the same work: releases worth naming, in prose, and the only place a milestone is named.
An epic is a line of work that takes many pull requests and has an exit criterion somebody could check. The tasks live inside it.
Where the reasoning goes #
In the epic, beside the work it justifies. There is no separate decision log: there was one, it reached fifty-odd entries before anything shipped, and what it mostly recorded was reasoning about things that turned out not to exist. An entry is only as good as the fact under it, and nothing checked the facts.
This directory is checked. The frontmatter builds the tables, the links have to resolve, and an epic points at work that either exists or does not — so a claim about something imaginary shows up as an item nobody can close. Reasoning that cannot survive next to the work it is about was not load-bearing.
The invariants the whole system rests on are in the repository's README, which is short on purpose.
The capabilities #
The epics are a decomposition of one list, written by the project's owner: a
conformant personal data server; ephemeral did:web accounts for agents;
lineage, model and execution environment tracking; third-party OAuth login for
those accounts; management of which scopes may be requested, which apps may be
granted anything, and which agents may write which record types; a dashboard
for that policy, with the policy stored in the owner's own personal data
server; bidirectional ownership verification; atproto private spaces; lexicons
for recent activity, memory and mentions; a firehose indexer; a frontend for
public and private activity; and a local development workflow with simulated
agent traffic.
That list is the mandate. Where anything here disagrees with it, the list wins and the epic is what changes.
The id is the commit scope #
Each epic's filename is its id, and that id never changes. plan/pds-writes.md
is pds-writes, so its commits read feat(pds-writes): …. That is why the ids
have no number prefix and why there is no order field: an identifier that has
to be rewritten when something else moves is not an identifier. Archiving moves
the file and never renames it.
plan is a valid scope too, for changes to this register.
Order is advisory #
The tables read top to bottom and that is the whole of the ordering. What
constrains the work is dependsOn, which says what genuinely cannot start
first, and status, which says what is blocked.
The sequence comes from order.txt, a list of ids and nothing else. An epic it does not name still appears, alphabetically, at the end of its table.
Status #
shipped — the exit criterion is met. Nothing is shipped yet. Several epics
have most of their work done and a demonstration running, which is not the same
thing: an epic ships when a stranger could check its exit criterion, and none
can be checked until records are real. The file stays after it ships, and moves
to complete/ when nothing is left open in it.
open — being worked on or ready to be. Everything is, including the four with
long ## Done lists.
blocked — cannot start until something in dependsOn lands. One epic is
blocked on something outside the project: spaces waits on a
specification that still calls itself a proposal.
continuous — no exit criterion. Worked whenever adjacent code is open.
declined — decided against. Not blocked, which is waiting. The file stays,
because a decision that is not written down gets made again.
The tables are generated #
The five tables below are output. scripts/gen-plan-readme.py reads every
epic's frontmatter and rewrites what sits between the <!-- generated: … -->
fences; everything outside a fence is hand-written and passes through
untouched. The plan-register prek hook runs it with --check, so a row that
disagrees with the file it points at fails the commit.
Adding an epic is one file and one command: write plan/<id>.md with the same
frontmatter keys, run scripts/gen-plan-readme.py, and stage both.
The structure and both scripts come from lance.blue's headquarters
repository. The one difference is that an epic names crates rather than
repos.
Complete #
Nothing open, nothing left to decide. These live in complete/, which does not
exist yet.
| id | title |
|---|
Shipped, with loose ends #
The exit criterion is met and something is still open in the file. Nothing yet.
| id | title |
|---|
Open #
| id | title | status |
|---|---|---|
| provenance | A record says which agent, which model, and what spawned it | open |
| index | One service watches every vouched server and says what changed | open |
| canvas | A person can watch a swarm work | open |
| pds-writes | A record is a signed commit in a repository | open |
| agent-accounts | An agent context becomes an account, and stops being one | open |
| account-types | Not every account is a session | open |
| scrobble | An agent says what it is working on, and the statement is its own record | open |
| write-policy | Which agents may write which record types | open |
| auth-types | Every credential this server accepts, and what each one may do | open |
| oauth | A third-party app signs in as an agent, with nobody at the consent screen | open |
| pds-xrpc | A client nobody here wrote can talk to this server | open |
| credentials | A session gets a credential without a wrapper process | open |
| scope-policy | An agent cannot be granted what its owner has not allowed | blocked |
| ownership | The human names the agents and the agents name the human | open |
| attestation | Where an agent was provisioned from is a claim somebody else signed | open |
| labels | What is true about an agent arrives as a label an app already draws | open |
| agent-sites | An agent publishes a page of its own, at a name the zone already serves | open |
| policy-store | Policy is the owner's record, in the owner's repository | open |
| app-allowlist | An app an owner has not admitted gets nothing | blocked |
| e-stop | An operator can halt the swarm when nothing else is working | open |
| policy-dashboard | The owner writes policy from a site this server does not run | blocked |
| ops-dashboard | A human can see what their agents are doing and stop them | blocked |
| memory | An agent remembers something past the end of its session | blocked |
| mentions | One agent addresses another, and the other finds out | blocked |
| spaces | Activity that is not public, without inventing a private tier | blocked |
| repo-scale | A write costs the same in an old repository as in a new one | open |
| store-scale | The state is larger than the process holding it | open |
| zone-scale | The zone runs out of names before it runs out of accounts | open |
| dev-setup | One command takes a new machine to a working stack | open |
| deploy | A named version runs somewhere that is not a laptop | open |
| stamp-contract | The hook stamps a tool it was told about, and the tool reads a contract it can name | open |
Continuous #
| id | title |
|---|---|
| local-dev | The whole stack runs on one machine, with traffic that looks real |
Not pursued #
Answered no. Nothing yet.
| id | title |
|---|
Where the lexicons are #
There is no lexicon epic. A zone.quernstone.* schema is a deliverable of
whichever epic needs the record. Doing it the other way round publishes a
collection name nothing ends up using, and a collection name cannot be taken
back once records exist in other people's repositories.