Public: anyone can read this; the crew can change it.
docs/VISION.md lands verbatim and every run reads it #5662
Check · Review · Land · Live done — Landed and live in production.
scout/forge:scout/972-docs-vision-md-lands-verbatim-and-every → main 1 commit fork 1 thread · 1 unresolved
4 files
changed +77
−0
CLAUDE.md +6
| @@ -4,6 +4,12 @@ Orientation for an agent editing forge. Read this first, then `README.md` (what | ||
| 4 | 4 | it is) and `docs/ARCHITECTURE.md` (why it's shaped this way). This file is the |
| 5 | 5 | rulebook: the invariants you must not break, and how to work here. |
| 6 | 6 | |
| 7 | **Read docs/VISION.md first: it says what the forge is for and the order of work.** | |
| 8 | ||
| 9 | **Done means reachable** — a person reaches it from the feed in two taps, an | |
| 10 | agent through the MCP, a test proves it, a look shows it. A function nobody can | |
| 11 | call is not done. | |
| 12 | ||
| 7 | 13 | The whole point of forge is that **one person can hold it in their head**. Every |
| 8 | 14 | change should leave it that way. When something fights you, step up and |
| 9 | 15 | understand the system before adding code — a workaround usually means the system |
docs/VISION.md added +26
| @@ -0,0 +1,26 @@ | ||
| 1 | # What the forge is for | |
| 2 | The forge is a social place for building. Everyone who joins gets a whole forge of their own: their apps, and a crew that builds them. People share what they make, take what others made and mold it, and the best of it rises through a visible tree of forks, while anyone can stay as private and as different as they like. Opening it should feel like opening X: you get it at once. Steering it should take one thought: type it, go. | |
| 3 | ||
| 4 | ## Order of work | |
| 5 | 0. **Trust, always first.** Agents are contained. Agent pulls are reviewed. The gate runs every test. Admin is a separate account from the everyday one, explained kindly and directly; using AI with admin stays possible but deliberate. Private by default, and always plain about who can see what. | |
| 6 | 1. **One front door: the feed.** Home is an X-style timeline that IS the git primitives: a post is a tell or an issue; a reply is a comment; a repost or quote is a share or a fork; a like is a signal written to the decision ledger; a crew member's posts are its runs, pulls and looks. The crew reads and writes through the same feed. There is no dev/studio split: one interface, with every developer depth (files, diffs, runs, terminal) one step deeper from any post. | |
| 7 | 2. **The explorer.** Apps, forges and people ranked by real metrics (use, forks, ships, likes, freshness), and trivially filterable to exactly what you want. Every app says "make it yours": one action forks it into your forge. | |
| 8 | 3. **The fork tree is the organization.** My forge is the public upstream; an organization's forge forks it; each person's forge forks their organization's. Every fork chooses how it follows its upstream. The tree is visible and a pleasure to browse; good changes bubble up as offers and flow down as updates. | |
| 9 | 4. **A forge in a link.** I (or my agent, through the MCP) create a forge for a person, a client or an organization: chosen apps (some forked from mine, some still autonomous so they see it cooking), a starter budget, an admin account, one link. First login shows their crew working right now in the feed, and three next steps: make your everyday account, open your apps, tell the crew something. They add their people; each new person gets their own forge that follows the organization's. A client list tracks who was sent what and what happened. | |
| 10 | 5. **Open to every agent.** Any agent or harness can find and use a forge: the MCP with OAuth (Claude app, Grok in a car); a role-aware, token-efficient manifest on every page saying what you can do here as who you are; standards metadata; and on a public app or repo, an outside person or agent can file a report or offer a pull without being taught how. | |
| 11 | 6. **Never lost.** A forge toolbar in every app and preview: where you are (app, environment, which pull this previews), who is working on it, comment on this page or its issue or pull, tell the crew from here, make it yours. Later: in a preview, a tint on what changed and its diff on selection. | |
| 12 | 7. **Steering is one thought.** Tell from anywhere: the feed composer, the toolbar, a phone share sheet, the MCP. | |
| 13 | ||
| 14 | ## How we build | |
| 15 | - A deterministic tool with deliberate noise: actions are explicit, previewed and receipted; AI judgment only where we say so. | |
| 16 | - The same action has the same shape for a person and an agent: a page and an MCP tool, in the same words. | |
| 17 | - Done means reachable: a person reaches it from the feed in two taps, an agent through the MCP, a test proves it, a look shows it. A function nobody can call is not done. | |
| 18 | - Far ideas go on the map behind what they depend on, and we trim honestly. | |
| 19 | ||
| 20 | ## The tests | |
| 21 | - **Link test:** someone opens a link to their new forge and, within a minute and without a word from me, sees a crew working and knows what to do next. | |
| 22 | - **Muse test:** an outside agent looking at a public forge app finds out how to report a problem or offer a change, and does it. | |
| 23 | - **Friend test:** someone I send an app to makes it theirs in one action. | |
| 24 | - **Tesla test:** any MCP client connects with OAuth and steers. | |
| 25 | - **Lost test:** from any app or preview you know where you are and can get home, comment, or tell the crew. | |
| 26 | - **Admin test:** a new owner is guided to a separate everyday account, told why in two sentences, and can still choose otherwise on purpose. |
src/crew/brief.ts +2
| @@ -66,6 +66,8 @@ export function systemPrompt(input: BriefInput): string { | ||
| 66 | 66 | agent.brief.trim() === "" ? "" : `\n${agent.brief.trim()}\n`, |
| 67 | 67 | `You are working in a clone of the repository on the branch \`${input.branch}\`. The remote \`origin\` is the forge; \`git push\` is already authenticated as you and the branch already tracks \`origin/${input.branch}\`. Git configuration is read-only here — do not try to change it, a plain \`git push\` is all you need.`, |
| 68 | 68 | "", |
| 69 | "Read docs/VISION.md first: it says what the forge is for and the order of work. Done means reachable — a person reaches it from the feed in two taps, an agent through the MCP, a test proves it, a look shows it. A function nobody can call is not done.", | |
| 70 | "", | |
| 69 | 71 | "How to finish:", |
| 70 | 72 | "- Commit your work with clear messages and push: `git push`.", |
| 71 | 73 | "- If `forge.json` declares a `check`, the forge runs it against every push to your pull, and that verdict is what lands it; a failing check comes back to you with its log. Before you push, run the type check and the tests that cover what you changed (and any the repository's CLAUDE.md or AGENTS.md says always to run) — not the whole check: the forge runs that once, and running it here as well costs the machine twice.", |
test/vision.test.ts added +43
| @@ -0,0 +1,43 @@ | ||
| 1 | /** | |
| 2 | * docs/VISION.md is read by every run (#972): CLAUDE.md and the brief every | |
| 3 | * crew member gets point at it and state the rule that done means reachable. | |
| 4 | */ | |
| 5 | ||
| 6 | import { describe, expect, test } from "bun:test"; | |
| 7 | import { readFileSync } from "node:fs"; | |
| 8 | import { systemPrompt } from "../src/crew/brief.ts"; | |
| 9 | ||
| 10 | const brief = (role: "planner" | "builder", isApp: boolean) => | |
| 11 | systemPrompt({ | |
| 12 | agent: { user: { username: "atlas", displayName: "Atlas" }, brief: "" }, | |
| 13 | repo: { ownerName: "alice", name: "forge", defaultBranch: "main" }, | |
| 14 | issue: { number: 1 }, | |
| 15 | branch: "atlas/1-x", | |
| 16 | forgeUrl: "https://forge.example", | |
| 17 | isApp, | |
| 18 | resuming: false, | |
| 19 | role, | |
| 20 | } as unknown as Parameters<typeof systemPrompt>[0]); | |
| 21 | ||
| 22 | describe("the vision", () => { | |
| 23 | test("the document exists and states the rule", () => { | |
| 24 | const text = readFileSync("docs/VISION.md", "utf8"); | |
| 25 | expect(text.startsWith("# What the forge is for")).toBe(true); | |
| 26 | expect(text).toContain("Done means reachable"); | |
| 27 | }); | |
| 28 | ||
| 29 | test("CLAUDE.md sends the reader to it first", () => { | |
| 30 | const text = readFileSync("CLAUDE.md", "utf8"); | |
| 31 | expect(text).toContain("Read docs/VISION.md first"); | |
| 32 | expect(text).toContain("**Done means reachable**"); | |
| 33 | }); | |
| 34 | ||
| 35 | test("every role's brief says to read it", () => { | |
| 36 | for (const role of ["planner", "builder"] as const) | |
| 37 | for (const isApp of [false, true]) { | |
| 38 | const text = brief(role, isApp); | |
| 39 | expect(text).toContain("Read docs/VISION.md first"); | |
| 40 | expect(text).toContain("Done means reachable"); | |
| 41 | } | |
| 42 | }); | |
| 43 | }); |
new above
offline
This only checks the title and one phrase. Also assert the section headings (Order of work, How we build, The tests) so a truncated doc fails.