Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions .agents/skills/plan-tickets/SKILL.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
---
name: plan-tickets
description: Queue a plan for every open ticket that has none, unattended.
disable-model-invocation: true
---

Queue plans for the tickets that need one. Nobody will answer you: never ask, decide yourself. Read every open ticket. Among those that are neither planned nor held by someone, take the ten most important and put one entry per ticket on the agent queue asking for that ticket's plan to be written, naming the ticket's file. Pick each entry's priority after reading the ticket, by a mix of sensible criteria: a ticket that looks low effort ranks higher. Skip a ticket whose plan is already asked for on the queue. You only queue work, you never do it: write no plan yourself. If no ticket needs a plan, say so and stop. If this project has no ticketing system or no AI queue, show an error to the user and stop.
2 changes: 2 additions & 0 deletions .agents/skills/tickets/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@ npx tickets list every open ticket, as one JSON array: file, tit
(priority, topics, github, effort, uncertainty, locked, lockedBy
absent when unset)
npx tickets show <file> one ticket: its text, its plan, who holds it
npx tickets meta when the tickets last caught up with the issue tracker:
{"lastImportedAt": <ISO 8601>}, or {} when no import was recorded
```

## Change
Expand Down
7 changes: 7 additions & 0 deletions .agents/skills/triage-consensual/SKILL.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
---
name: triage-consensual
description: Put the significant, consensual tickets on the project's agent queue, unattended.
disable-model-invocation: true
---

Choose consensual work for the agent queue. Nobody will answer you: never ask, decide yourself. Read every open ticket with its plan. Pick only the tickets that are significant, no quick wins, and consensual: no open question, no variability, one fairly obvious plan. Put each picked ticket on the agent queue as a link to the ticket labeled with its title, at the ticket's own priority, 5 when it has none. Skip a ticket already on the queue or held by someone. You only queue work, you never do it: the only thing you change is the queue. Do not implement a ticket, however clear its plan; a human can still veto it on the queue before an agent works it. If nothing qualifies, say so and stop. If this project has no ticketing system or no AI queue, show an error to the user and stop.
7 changes: 7 additions & 0 deletions .agents/skills/triage-quick/SKILL.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
---
name: triage-quick
description: Put the quick-win tickets on the project's agent queue, unattended.
disable-model-invocation: true
---

Choose quick wins for the agent queue. Nobody will answer you: never ask, decide yourself. Read every open ticket with its plan's effort and uncertainty. Pick the tickets whose plan shows a quick win: a low effort and no uncertainty. Put each picked ticket on the agent queue as a link to the ticket labeled with its title, with a sensible priority, and consider bumping the lowest-effort tickets so agents work them first. Skip a ticket already on the queue or held by someone. You only queue work, you never do it: the only thing you change is the queue. Do not implement a ticket, however small its plan; a human can still veto it on the queue before an agent works it. If nothing qualifies, say so and stop. If this project has no ticketing system or no AI queue, show an error to the user and stop.
7 changes: 7 additions & 0 deletions .agents/skills/update-tickets/SKILL.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
---
name: update-tickets
description: Bring the project's tickets up to date with its issue tracker, unattended.
disable-model-invocation: true
---

Bring the tickets up to date with the project's issue tracker. Nobody will answer you: never ask, decide yourself. Note the current UTC time first, in ISO 8601: it is the import time you record at the end, and noting it before you fetch is deliberate, so an issue edited while you work is picked up by the next update instead of being missed. Read when the tickets last caught up with the tracker. If there are tickets but no such time, or the tracker cannot be reached, or you are not logged in to it, show an error to the user saying which of those it is and stop. If there are no tickets at all, treat it as a first import and bring every open issue across. Otherwise fetch only the issues and the discussion changed since that time. Reconcile, one ticket per issue: an issue with no ticket yet gets one; an issue that has a ticket has it updated in place, keeping its file name and its plan, and marking the plan outdated when the change calls for it; a comment is folded in only where it changes what the work is, never pasted; an issue now closed has its ticket closed. Record the time you noted as the new import time, and say in one line how many tickets you added, updated and removed. If this project has no ticketing system, show an error to the user and stop.
1 change: 1 addition & 0 deletions .claude/skills/plan-tickets
1 change: 1 addition & 0 deletions .claude/skills/triage-consensual
1 change: 1 addition & 0 deletions .claude/skills/triage-quick
1 change: 1 addition & 0 deletions .claude/skills/update-tickets
5 changes: 3 additions & 2 deletions LOGIC.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
The Framework: autonomous AI programming. The user registers repositories as projects in a browser dashboard and states what to build or fix; a coding agent — Claude Code or Codex, on the user's own subscription — works the task unattended in a checkout [3] of its own, stops only for decisions a human must make, and hands the result off as a pull request. While nobody is at the keyboard, a scheduler the project's own hook starts with the dashboard works the agent queue [7] one entry at a time, each entry by an agent that publishes its own pull request set to merge on green, and the daemon keeps the pull requests it opened green — both standing down before unattended work could eat into the quota a human will want. The product never calls a model itself, and the user's own checkout is never touched.
The Framework: autonomous AI programming. The user registers repositories as projects in a browser dashboard and states what to build or fix; a coding agent — Claude Code or Codex, on the user's own subscription — works the task unattended in a checkout [3] of its own, stops only for decisions a human must make, and hands the result off as a pull request. While nobody is at the keyboard, a scheduler the project's own hook starts with the dashboard works the agent queue [7] one entry at a time, each entry by an agent that publishes its own pull request set to merge on green, and keeps the queue fed on a schedule: issues become tickets, tickets get plans, planned tickets are queued, and the daemon keeps the pull requests it opened green — both standing down before unattended work could eat into the quota a human will want. The product never calls a model itself, and the user's own checkout is never touched.

## Context

Expand Down Expand Up @@ -50,7 +50,8 @@ The Framework: autonomous AI programming. The user registers repositories as pro
- `packages/agent-data` — a branch of the project's repository used as a file store: the `agent-data` branch [6], checked out under `.branches/`, written through one sync → commit → push cycle that re-applies when a push loses a race. A library, not a skill: read by code, never by an agent. Every skill depends on it; nothing else does.
- `packages/skill-branches`, `packages/skill-tickets`, `packages/skill-queue`, `packages/skill-logs` — the four skills [8]: an agent's own checkout [3] and branch; the tickets with their plans and claims; the agent queue [7]; the record of every run [16]. Tickets, queue and runs live on the `agent-data` branch, never on a code branch, so the default branch stays code only. No skill depends on another.
- `packages/skill-work-queue` — the first command skill: a job for an agent, one skill file and no code, composing the four skills [8] without naming one; a project tracks it as `.claude/skills/work-queue`, and the scheduler fires it by its slash command, `/work-queue`. One package per command, `@gemstack/skill-<command>`; nothing depends on it.
- `packages/agent-scheduler` — the scheduler: a tool like `agent-driver`, one command line and one small process per project, that reads the project's tracked `agent-schedule.md`, ticks every minute, and starts one agent per due command in its own checkout, recording every run on the `agent-data` branch. Depends on `agent-driver`, `agent-data`, the branches and the logs packages; never on The Framework, which never depends on it.
- `packages/skill-update-tickets`, `packages/skill-plan-tickets`, `packages/skill-triage-quick`, `packages/skill-triage-consensual` — the routine commands, one package each of the same shape: bring the tickets up to date with the issue tracker, queue a plan for every unplanned ticket, queue the quick wins, queue the consensual work. The schedule says how often at most each runs.
- `packages/agent-scheduler` — the scheduler: a tool like `agent-driver`, one command line and one small process per project, that reads the project's tracked `agent-schedule.md` (per command a check that says there is work, an interval that says how often at most, or both), ticks every minute, and starts one agent per due command in its own checkout, recording every run on the `agent-data` branch. Depends on `agent-driver`, `agent-data`, the branches and the logs packages; never on The Framework, which never depends on it.
- `packages/chrome-extension` — the far end of the Claude web bridge [12], a Chrome extension reading claude.ai in a signed-in browser; it talks to the daemon over HTTP only.
- `packages/the-framework.ai` — the marketing site at https://the-framework.ai; it presents the product and shares no code with it.
- `.github/workflows` — every push builds, type-checks and tests the monorepo; the website deploys itself from the default branch; and one workflow is the far end of the `github-actions` driver implementation, running one turn per workflow run.
Expand Down
6 changes: 5 additions & 1 deletion agent-schedule.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
# Agent schedule

One line per command. The command is the project's `.claude/skills/<command>`. `when` is a check, run at the repository root: the command is due while the check prints a JSON value that is not empty. `cap` is how many runs of the command may be in flight at once, across every machine that shares this repository.
One line per command. The command is the project's `.claude/skills/<command>`. `every` is how often at most: the command is due only once that long has passed since its last recorded start. `when` is a check, run at the repository root: the command is due while the check prints a JSON value that is not empty. A line carries one or both; with both, an agent starts only when both hold. `cap` is how many runs of the command may be in flight at once, across every machine that shares this repository.

- work-queue: when `npx queue`, cap 1
- update-tickets: every 1h, when `gh issue list --limit 1 --json number --search "updated:>=$(npx tickets meta | jq -r .lastImportedAt)"`
- plan-tickets: every 6h, when `npx tickets list | jq '[.[] | select(.planned or .locked | not)]'`
- triage-quick: every 6h
- triage-consensual: every 7d
1 change: 1 addition & 0 deletions packages/LOGIC.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ The deliverables The Framework ships, one directory each. The product is the `fr
- **The `queue` skill** (`skill-queue/`) - the `@gemstack/skill-queue` npm package: the agent queue on the `agent-data` branch, the `queue` command that reads it, adds an entry at a priority and takes one off, and the skill text. Depends on `agent-data`.
- **The `logs` skill** (`skill-logs/`) - the `@gemstack/skill-logs` npm package: the record of every run agents made on a project, on the `agent-data` branch, and the read-only `logs` command; the product writes every run through it. Depends on `agent-data`.
- **The `work-queue` command** (`skill-work-queue/`) - the `@gemstack/skill-work-queue` npm package: a command skill, one `SKILL.md` and no code, the job of working one queued task off the agent queue; it composes the capability skills of a project without naming one. One package per command; a project tracks its skill file under `.claude/skills/<command>`, and the scheduler fires it by its slash command.
- **The routine commands** (`skill-update-tickets/`, `skill-plan-tickets/`, `skill-triage-quick/`, `skill-triage-consensual/`) - four more command skills of the same shape, one package each: bring the tickets up to date with the issue tracker; queue a plan for every ticket that has none; put the quick-win tickets on the agent queue; put the significant, consensual tickets on the agent queue. Each is fired by the scheduler on the interval the project's schedule gives it.
- **The scheduler** (`agent-scheduler/`) - the `agent-scheduler` npm package: a tool, not a skill, with one command line (`tick`, `run`, `start`, `stop`, `status`) and one small process per project; it reads the project's tracked `agent-schedule.md`, pulls the `agent-data` branch [4], counts the runs in flight there, and starts one agent per due command in its own checkout through the branches package and agent-driver [2], the run recorded through the logs package. Names no skill. Depends on `agent-driver`, `agent-data`, `skill-branches` and `skill-logs`; nothing depends on it.
- **The Claude web bridge's extension** (`chrome-extension/`) - a Chrome extension, not an npm package: the far end of the Claude web bridge [5], reading claude.ai in a signed-in browser. Talks to the product over HTTP only.
- **The website** (`the-framework.ai/`) - the marketing site at https://the-framework.ai. Presents the product; shares no code with it.
Expand Down
8 changes: 8 additions & 0 deletions packages/agent-scheduler/DECISIONS.md
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,14 @@ decision. An AI proposes a bullet and asks; it never adds or rewrites one.
empty), over the tool reading the queue (the tool would know a skill), and over a bare
clock (empty runs). A list line the parser cannot read is skipped and named, never
guessed.
- A schedule line paces a command two ways, alone or together: `when` says there is work
(the check's output), `every` says how often at most (the least time since the command's
last recorded start, read off the run records on the branch, so every machine agrees and
nothing new is stored). A routine whose run changes nothing cannot be paced by a check
alone: it would start every minute. Picked over a rotation of the routines in a fixed
order behind an empty queue (one line then depends on another, and idle it started an
agent every 30 minutes), and over a clock time (`at 09:00`: machine-local, and two
machines fire twice). Order is what the numbers say.
- The state, `.agent-scheduler/state.json`, untracked, per user, hidden through git's
exclude file the way `.branches/` is: on or off, keep-alive, the model, the spend cushion,
the scheduler's pid, the last tick and what it decided. Nothing the tool knows is only in
Expand Down
4 changes: 2 additions & 2 deletions packages/agent-scheduler/LOGIC.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ The `agent-scheduler` package: a standalone tool, like `agent-driver`, that star

## Context

**User story**: the user writes `- work-queue: when \`npx queue\`, cap 1` in `agent-schedule.md`, commits it, and runs `agent-scheduler start`; from then on, whenever the project's agent queue holds an entry, one agent works it in its own checkout and opens a pull request, never two at once, and never past the share of the week's quota that has elapsed; the user reads why nothing started (`not due`, `cap reached (…)`, `quota: …`) in the state file or on a dashboard, changes the model or the spend cushion for their own machine, and runs `agent-scheduler stop` to turn it off while the agents in flight run to the end.
**User story**: the user writes `- work-queue: when \`npx queue\`, cap 1` and `- triage-quick: every 6h` in `agent-schedule.md`, commits it, and runs `agent-scheduler start`; from then on, whenever the project's agent queue holds an entry, one agent works it in its own checkout and opens a pull request, never two at once, and at most every six hours one agent triages the tickets, and never past the share of the week's quota that has elapsed; the user reads why nothing started (`not due`, `cap reached (…)`, `quota: …`) in the state file or on a dashboard, changes the model or the spend cushion for their own machine, and runs `agent-scheduler stop` to turn it off while the agents in flight run to the end.

**Business logic story**: the daemon of The Framework used to watch the branch and start agents on its own rules, in its own memory. This tool replaces that with files and small processes: the schedule is a tracked file a person writes; the tool's state [12] is an untracked JSON file under `.agent-scheduler/`, per user; a run in flight is a run record [11] on the `agent-data` branch with `status: running`, so two machines sharing the repository count the same runs against a cap; a run is one detached process of the tool's own, `agent-scheduler run`, that makes a checkout through the `branches` package, prompts Claude Code once through `agent-driver` with no system prompt (the command's skill file is the whole instruction, and the agent publishes its own work with the `branches` skill), then writes the run record and reclaims [13] the checkout; and the scheduler's process [14] is a loop of ticks that holds nothing a restart would lose. The spend-boundary rule is copied from The Framework rather than imported, because this tool depends on `agent-driver`, which reads the quota, and not on The Framework, which draws the panel.

Expand Down Expand Up @@ -42,4 +42,4 @@ The `agent-scheduler` package: a standalone tool, like `agent-driver`, that star
- A tick first pulls the `agent-data` branch [5] (a pull that fails ends the tick: a stale branch must start nothing), then sweeps [6], then, when the state is on and the schedule exists, decides per command [3] in the cheapest order: the project has the command; the check says due; the cap [8] is not reached, counted from the run records [11] saying `running` on the branch, whatever the machine; the quota [9] has headroom, read only when everything else says start. A command that passes gets a run record written as a marker, `status: running`, with the tool's mark (`caller.scheduler`: the command and this machine; the run's pid joins it once its process exists); the tool counts again, withdraws the marker if another machine's landed first past the cap, and otherwise spawns the run [7] as a detached process.
- The run makes a checkout [10] through the `branches` package, keeps a live log in the checkout in the shape The Framework's dashboard reads, prompts Claude Code once with `/<command>` and lets the agent's own loop run to the end; the agent commits, names its branch and opens a pull request itself. The run then reads the pull request back off the branch, writes the run record over the marker with the card and the diary, and reclaims [13] the checkout under the `branches` rule: a dirty tree, or a branch not on the remote, keeps it.
- On every tick the sweep records and reclaims what a run of this machine could not: a live log still `running` under a dead pid is recorded `failed`; one that ended but was never recorded is recorded as it ended; a marker of this machine with no checkout behind it is recorded `failed` with the spawn's stderr, else `stopped`. A running record from another machine is never touched: only that machine's sweep, or a person, changes it, and a machine that never comes back leaves its command capped on purpose.
- Every decision of the tick is one line in the state (`started <id>`, `not due`, `cap reached (…)`, `quota: …`, `no such command in this project`, …), so a dashboard or a person reads why nothing started without a log.
- Every decision of the tick is one line in the state (`started <id>`, `not due`, `not due (last start 2h ago, every 6h)`, `cap reached (…)`, `quota: …`, `no such command in this project`, …), so a dashboard or a person reads why nothing started without a log.
Loading
Loading