12. Refinement
Refinement is where a rough idea grows into a story before it goes to the backlog. The session keeps the idea, its state, a log, the architect's brief and the talk (questions, answers and a map of rules, examples and open questions). On the session page you can ask the architect to look at the code (see below).
Start a session. Click New session (or choose Refine an idea first or Refine an existing issue on Start work). Choose the kind: An idea or An existing issue. For an idea, choose a repository, write your idea in your own words (required, up to 10,000 characters) and, if you like, a title (optional, up to 120 characters). When the title is empty, the first line of the idea is used. For an existing issue, choose a repository and give the issue number (see below); a blank, zero or non-number issue is refused with "Give the issue number." and nothing is sent. Only GitHub repositories from My repositories are offered. If you have none, the dialog links to that page. If the server refuses, its sentence shows in the dialog. What you typed is kept in page memory when you close the dialog or the request fails, and is cleared after the session is made. Nothing is written to GitHub.
Refine an existing issue. Click Refine an existing issue next to New session (it opens the same dialog with the kind "An existing issue"). Under the kind the dialog says that a session from an issue cannot be published yet. Choose one of your repositories and give the issue number (for example 12 or #12). The issue is read from GitHub; nothing on GitHub changes. If the server refuses (the Foundry is building or has built the issue, it is closed, it does not exist, or you already have a session for it), the dialog shows the reason and stays open. The session page then says "From issue #N" with a link. If the issue has the build label, the page warns that the Foundry may start building it while you refine it, and offers Remove the build label. The label is removed only when you press that button, with the repository's GitHub sign-in, and only by the owner of the session. After that the warning is gone. The watcher is not held back: until the label is removed, the Foundry may start building the issue.
Start from an existing issue (server; the button above uses it). POST /api/refinement also accepts { "repo": …, "issue": <number> } instead of an idea. The issue is read from GitHub with the repository's sign-in; nothing is written to GitHub. The issue's title becomes the session title (up to 256 characters) and its title and text become the idea. The session keeps source: the issue number, link, and the title, text and updated_at it had when it was read (GET /api/refinement/:id returns it). When the text has the story format that Preview writes, the session gets one draft with the fields filled, all marked as typed by a person; text the fields cannot hold goes into the notes under its heading, and "Accepted anyway" is not taken. Without the story format, you get the idea only and no draft. Hidden Foundry markers and the "Refined in Spaghetti Code Foundry by …" note are left out. A text over the idea limit is refused, not cut. It is refused with a reason when the issue does not exist (404), is a pull request (400), is closed (409), or the repository is not yours (403). It is refused with 409 when the Foundry is building or has built the issue: a live or queued run, a Foundry status label (working, waiting, needs info, done; a watcher's own names count), or a run with a pull request, unless that pull request is closed and not merged. An issue with only a failed run, or only the failed label, is accepted. An issue for which you already have an open session is refused with the id of that session. When the issue has the build label, source.buildLabel says so. A session from an issue cannot be published yet (409) until write-back exists.
Backlog readiness. Click Backlog readiness on the Refinement page to see which open issues of a repository are not ready. Choose one of your repositories. The list shows the open issues the Foundry is not building and has not built (the same rule as "Refine an existing issue"), newest first, with the number (a link to GitHub), the title and four marks, done by code only: Acceptance criteria (a section with at least one item), Value sentence ("As …, I want …, so that …"), Depends on (every issue named there exists; hover a ✗ to see which were not found) and No open questions (no "Open questions" heading with content, and no unchecked question item). The marks are hints; nothing is blocked by them. Press Refine to start a session from that issue and open it. When you already have an open session for the issue, the button reads Open session. GitHub's newest 100 issues and pull requests are read; when that page is full, the view says that older open issues may be missing. When GitHub cannot be read, the view says so and tells you to check the repository's sign-in under My repositories. The view starts no architect run, writes nothing to GitHub and adds or removes no labels; the watcher is not changed. It is not shown in a preview ("View as user"). Server: GET /api/refinement/backlog?repo=owner/name (see the route table); only the owner of the repository can read it.
States. A session is exploring, drafting, ready, published or dropped. It starts as exploring. The state changes only by what you do. The first story draft makes it drafting, and removing the last draft makes it exploring again. Drop and Restore change it too. A session is ready when it has drafts and every draft is ready (see "Ready" below); a change that makes a draft drafting again makes the session drafting. It becomes published when every draft of the session has a GitHub issue (see "Publishing"); with only some published it stays as it was. Later steps add the others.
The session page. It shows the idea, the Context brief (see below), the Questions and Map parts (see "The talk" below), the Story drafts (see "Story drafts" below) and the log: who did what, and when, also when the architect was asked, wrote the brief or could not finish. The list shows title, repository, state and last change; an admin also sees the owner. See "The session page" below for how the page is laid out.
The session page#
The session page #/refinement/:id is one workspace. The title, the state, the repository and the Rename, Drop and Restore buttons stay on top. Under them is a row of five parts; one part is shown at a time:
| Part | Shows | State on its button |
|---|---|---|
| Idea and brief | the idea and the architect's context brief | "none", "made", or "working" |
| Conversation | the questions, the proposals and the map | the open questions, for example "2 questions open" |
| Story drafts | the drafts, their readiness, impact and suggestions | "n drafts, m ready" |
| Hand off | publishing to GitHub | "n on GitHub", or "nothing ready" |
| Log | who did what, and when | — |
- Next. A line "Next:" names the next step: ask the architect to look at the code, answer the questions, add a draft, check readiness, or publish. Click it to go to that part. It is advice only. Nothing is done for you, and you can open any part at any time.
- Which part opens. A new session opens on Idea and brief. A session with drafts opens on Story drafts. The part you choose is kept for that session while the page is open, also when the page refreshes by itself. It is not kept after you close the page.
- Nothing is lost. Switching parts hides a part; it does not rebuild it. Text you typed in a draft or an answer is kept and is still saved. Leaving the page saves it as before.
- The architect's line. While the architect works, its status line shows in whichever part is open.
- Keyboard and screen readers. The row is a tab list. Use the left and right arrow keys to move between the parts. Enter or Space chooses one. The chosen part keeps the focus when the page refreshes.
- Rules are the same. Who may change what, the read-only preview, dropped sessions, a hidden brief, talk or drafts, a missing repository, and publishing only after you confirm are all unchanged. The address
#/refinement/:idis unchanged.
Rename, drop, restore. Rename changes the title. Drop (after a confirmation) takes the session out of Open sessions. Find it again under Dropped: Restore brings it back in the state it had. A dropped session is removed after 30 days.
Who may do what. You see and change only your own sessions. An admin sees all sessions and who owns them, and may drop one, but cannot rename or restore it. In the log, you see an admin's action as "an administrator".
When something goes away. If you remove the repository from My repositories, the session stays readable; the page says so, and it works again when you add the repository back. If an admin deletes your account, your refinement sessions are deleted with it.
Limits. 200 sessions per account; dropped sessions count until they are removed. 1,000 log entries per session; after that the session can only be dropped. In the talk (see below): 100 entries per list, 50 waiting proposals and 50 own questions. In story drafts (see below): 20 drafts; title 120 characters on one line; who, what and why 500 each; 50 criteria of 500; out of scope and notes 5,000 each; 20 depends-on items. A full list or log answers 400 with a plain sentence. Nothing is removed to make room.
Story drafts#
A session keeps story drafts, so that what you write is saved. A draft has a title, who, what and why (the parts of "As …, I want …, so that …"), acceptance criteria (a list), out of scope, depends on (a list) and notes for the builder. A new draft is empty: nothing is filled in from the idea, the brief or the map. A session has at most 20 drafts and one optional Epic that applies to all of them.
On the page. The Story drafts part lists the drafts by title ("Untitled draft" when empty; "No story drafts yet." when there are none). New draft adds an empty one and opens it. Open shows a draft on the session page, Close hides it, Remove draft removes it after a question. An open draft has these fields in order: Title; "As …", "I want …", "so that …"; Acceptance criteria; Out of scope; Depends on; Notes for the builder. The Epic of the session (an issue number) is set with Set Epic and cleared with Clear Epic.
Saving. What you type is saved by itself one second after you stop, and when you leave the field. The page says "Saving…", "Saved", or the server's sentence when a save failed. A failed save keeps your text in the field and your next change tries again. The page you see never overwrites text that is not saved, also while the architect works.
When you are signed out. The page says "sign in first" and keeps your text. Copy it, load the page again and sign in.
Leaving the page. The browser asks first while text is not saved.
Not saved. Text whose draft or criterion was removed elsewhere, or typed just before the session could no longer be changed, shows in a Not saved card until you discard it or load the page again.
Acceptance criteria. Type in the last empty field to add one. An emptied criterion keeps its text when you leave it; use Remove to take one away.
Depends on and Epic. For Depends on, type an issue number ("12" or "#12") and press Add issue, or choose another draft of this session and press Add draft; Remove takes one out. The Epic is a whole number from 1. A wrong number is refused with a message.
Preview. Under the fields, Preview shows the story as it will look on GitHub: the title, the Epic line, the sentence, the criteria with check boxes that cannot be ticked, Out of scope, Notes for the builder and Depends on. Your text shows as typed, also when it looks like Markdown. Show as Markdown shows the exact text; Show the preview goes back. The preview follows what is saved.
Who sees fields. Fields and buttons show only on your own, open session whose repository is in My repositories. A dropped session, another account's session (admin) and a session whose repository is gone show the drafts as text. A hidden list says that it is not shown.
The calls. The page uses these; all answer with the session.
POST /api/refinement/:id/draftsadds an empty draft (201).PUT /api/refinement/:id/drafts/:didsaves what you typed, for example{ "title": "Export a report", "who": "an admin", "what": "to export a report", "why": "I can share it", "criteria": [{ "text": "It downloads" }], "dependsOn": [{ "issue": 12 }] }.DELETE /api/refinement/:id/drafts/:didremoves a draft, and it from the depends-on lists of the other drafts.PUT /api/refinement/:id/epicwith{ "issue": 73 }sets the Epic;{ "issue": null }clears it. It must be a whole number from 1; it is not checked against GitHub yet.
Only what you send changes. A field you leave out stays. An empty field ("", spaces or null) is removed. A list is sent whole: an item with a known id and the same text stays as it is, a known id with a new text is changed, an item without id is new, and an item you leave out is removed. So send the id of every item you keep: the same text without its id is stored as a new item. An unknown or repeated id answers 400 ("load the session again").
Where a text came from. Every text field and list item has from: typed, accepted (from a suggestion) or accepted-edited. The server sets it and ignores a from you send: new text is typed, and changing an accepted text makes it accepted-edited.
Suggestions from the architect#
You can ask the architect for a proposal for one field of a draft. It is only a proposal: it waits beside the draft (suggestions) and is in no field and not in preview until you accept it.
POST /api/refinement/:id/drafts/:did/suggestwith{ "field": "title" }(title,who,what,why,criteria,outOfScope,dependsOnornotes) starts an architect run and answers 202. The rules of a round apply: only the owner, a brief is needed, one architect run per session (the runs of your other sessions wait in line), and a paused run is resumed by the same call (the same draft and field).criteriaanswers 409 when the map has no rule and no example.POST …/drafts/:did/suggestions/:sid/acceptwith{}puts it in asaccepted: a text field is replaced, a list gets one more item. With{ "text": "…" }(Edit and accept) your text goes in asaccepted-edited; this is not possible for depends on (400). The suggestion is gone after that.POST …/drafts/:did/suggestions/:sid/rejectwith an optional{ "reason": "…" }(at most 300 characters) removes it and keeps its text and reason with the draft (the newest 30). The next suggestion run of the session gets them; they are used in this session only.
What the architect gets. The idea, the brief, the map (rules and examples are numbered R1, E1), the draft as it is now, the other drafts and the rejected suggestions with their reasons. It works from this text and opens a file only to check a claim. A run costs at most $1.
One or many. One suggestion for a text field; up to 10 for acceptance criteria and depends on. A new run replaces the waiting suggestions of its field; at most 20 wait per draft. Each criterion names the rule or example it comes from (tie) and says what can be observed; one whose rule or example is not in the map is left out. The tie stays when you edit the criterion; when the map entry is removed, the tie is dropped and the waiting suggestions from it go. Depends-on suggestions are an issue number or another draft of the session; anything else is left out.
Very large sessions. The task is at most 90,000 bytes. Then the brief is cut first, then map lines and other drafts, and the draft last; a "Left out" part names what is missing.
Log. The log tells that a suggestion was asked for (with the field), that the architect suggested, and that a suggestion was accepted or rejected.
On the page. Every field of an open draft has Suggest. Without a brief the page says to ask the architect to look at the code first; for acceptance criteria with no rule or example in the map it says to accept one first. While the architect works, a line next to the field says "The architect is writing a suggestion." and the Suggest button is gone. A paused run shows its reason with Ask again, a failed one with Try again. Text you typed and have not saved is saved first; if that save fails, nothing is asked.
A suggestion shows next to its field, marked "Suggested", with three buttons:
- Accept puts it in. On a text field that already has text, the page asks before it replaces it.
- Edit and accept opens a dialog with the text to change (not for Depends on).
- Reject opens a dialog with an optional short reason.
A suggested criterion shows the rule or example it comes from. Criteria are decided one by one. After a decision the field shows the new text and the suggestion is gone; text you typed in other fields and have not saved is kept. Every field and every list item with text shows where it came from: "typed", "accepted" or "accepted, then edited". A dropped session, another account's session and a session whose repository is gone show the waiting suggestions and these marks without buttons. If a suggestion run belongs to a draft that is not open, its line shows at the top of Story drafts. The Context brief part does not show the line of a suggestion run. All texts are shown as text. No new route is used.
Remarks from code checks. Every draft in the session view has remarks, computed from its text on every read and save. No AI call is made and nothing is stored. They cover every field but the notes for the builder. Each remark has field (and item, the criterion id), kind, word (what was found) and text (a plain sentence).
vague: a word that cannot be checked, from a fixed list (for example "fast", "easy", "simple", "etc").plan: text that reads like an implementation plan: a code block, a path with a file extension, a call likesave(), or build steps ("first add a table, then …"). The remark says that this belongs in the build step. Text in backticks and web addresses are not flagged, so a story can name an API route or a setting on purpose.
Remarks are advice. They never block a save or anything else.
Review by the architect. POST /api/refinement/:id/drafts/:did/review (no body) starts an architect run and answers 202 with the session. The rules of a round apply: only the owner, a brief is needed, one architect run per session (the runs of your other sessions wait in line), a paused run is resumed by the same call, and a failed run changes nothing. The architect gets the idea, the brief, the map and the draft. It only points out weak spots; it changes no field and proposes no new text. Only this call starts an AI call; saving a draft never does.
The result is stored with the draft as review: { at, remarks }, at most 20 remarks. Each remark has field (and item for a criterion), kind and text (one or two sentences). The kinds are uncheckable (a criterion that cannot be checked), vague, contradiction (with another criterion or a rule of the map), how (it says how to build, not what is wanted) and plan. A new review replaces the old one. A remark about a text that has changed or moved since the review has stale: true.
The architect's view of a draft. POST /api/refinement/:id/drafts/:did/impact (no body) starts an architect run of kind impact and answers 202 with the session. The same rules as a review apply: only the owner, a brief is needed, the draft must not be empty, one architect run per account, and a paused run is resumed by the same call. The task lists the other drafts as D1, D2, … so the architect can name them in dependsOn and dependents; the answer stores them as draft ids, and a statement about a draft that was not in the task is left out. A run keeps the flow's limit of $3, because it must read the code and up to 50 issues.
When the run ends, the checked view (see ask=impact below) is stored with the draft as impact and replaces an older one. No field of the draft changes and the session state does not change. The session answer shows each draft's impact with the basis (found or estimate) of every statement, and outOfDate: true when the title, who, what, why, a criterion, out of scope or depends-on changed since the view was asked. A wrong form fails the run with "The architect's answer did not have the agreed form" and the old view stays. The task also has a part "Areas the Foundry knows": the AREAS: of the newest Foundry run of each issue of the repository (at most 50 issues; runs of all accounts; only paths and the issue number) and the areas in the stored views of your other drafts on this repository. The view shows an overlap with another draft by the draft's title, marked as a draft. The view is not shown while the repository is not in My repositories. The log tells impact-asked and architect-impact.
Ways to split a draft. POST /api/refinement/:id/drafts/:did/split starts an architect run of kind split and answers 202 with the session. The body is optional; it may be { "own": "…" }, your own way, one text of at most 500 characters (anything else gives 400). The same rules as a review apply: only the owner, a brief is needed, one architect run per account, and a paused run is resumed by the same call. The answer is 409 when the draft has fewer than 2 acceptance criteria. The task lists the criteria as C1, C2, …; your own way goes into the task under a heading that shows its length. A run keeps the $1 limit of a review. Nothing is split by this.
Confirming a split. POST /api/refinement/:id/drafts/:did/split/confirm takes { "way": 0, "parts": [{ "title": "…", "sentence": "…", "criteria": ["<criterion id>"], "dependsOn": [1] }], "unplaced": ["<criterion id>"] } and answers 201 with the session. No architect run starts. way is optional (0 to 2, one of the stored ways). There must be 2 to 6 parts, each with a title. dependsOn lists part numbers starting at 1; a part may depend on an earlier part only. Every criterion of the draft goes in exactly one part or in unplaced; a draft with no or one criterion can be split by your own plan. Each part becomes a new draft at the end of the list, in plan order, with its criteria and copies of the original's out of scope and notes. The first part also gets copies of the original's dependencies. The original stays as a record: it keeps the unplaced criteria, shows state: "split", is never ready, and is not published. A draft that is already split, is a part, or is published gives 409. There can be at most 20 drafts after the split. Removing a part takes it out of the original's list; removing the original keeps the parts as normal drafts.
Moving a criterion between the parts of a split. POST /api/refinement/:id/drafts/:did/criteria/:cid/move takes { "to": "<draft id>" } and answers 200 with the session. The criterion goes to the end of the target draft. It works from part to part, from the original to a part and from a part back to the original; this is the one change allowed on a split original. to must be another draft of the same split (the original or one of its parts), otherwise 400 a criterion can only move between a split draft and its parts. A body without to gives 400 send to: the draft to move the criterion to. An unknown draft or criterion gives 404, a full target (50 criteria) gives 400, and a draft that is already on GitHub, as source or target, gives 409. The readiness check of both drafts is cleared, and the log gets criterion-moved with the criterion text. The view of a split original has partWarnings when there are any: layer for a part without a criterion, and same-code for two parts whose impact areas overlap while neither depends on the other, directly or through other parts (areas lists up to 5 of the overlapping areas of the first part).
Merging two drafts. POST /api/refinement/:id/drafts/:did/merge takes { "with": "<draft id>" }, merges that draft into this one, removes it and answers 200 with the session. It is for undoing a split that went too far. No architect run starts. The first draft keeps its title, who, what and why; an empty one is taken from the second. The criteria of the second come after those of the first (50 at most, otherwise 400). Out of scope and notes: equal texts are kept once; different texts are joined with an empty line, and a joined text that is too long gives 400. Depends-on is the union of both without the two drafts themselves (20 at most, otherwise 400); other drafts that depended on the second now depend on the first. Waiting suggestions, review, impact, split proposal and readiness check of the merged draft are cleared; rejected suggestions of both are kept (the newest 30). If the second was a part of a split, the original is updated. No part may depend on a later part of its split: after a merge such a link is removed and named in the log detail. A split original, or a draft already on GitHub, gives 409; a draft merged with itself gives 400. The log gets drafts-merged.
A split original is read-only. On a draft that is split, you work on the parts instead. These answer 409 with this draft is split; its parts are worked on instead and change nothing: saving fields, accepting or rejecting a suggestion, move to notes, the review label, the readiness check, accept anyway, and removing an "accepted anyway" mark. Asking the architect for a suggestion, a review, an impact view, a readiness judgement or ways to split on the original is 409 too. Removing the original still works. When the last part is removed, the original can be edited again. A part takes suggestion, review and readiness check like any draft. If a run was paused and its draft is split before you resume it, asking again is 409 and the paused run is cancelled and marked failed with The draft was split while the run was paused; the next ask in the session is not blocked. If a run is working while its draft is split, its result is not stored and the run fails with The draft was split while the architect was reading. Undo is partial: removing a part does not bring back its criteria. They are gone with the part.
When the run ends, the checked ways (see ask=split below) are stored with the draft as split and replace older ones; the C numbers are stored as criterion ids. No field of the draft and no session state changes. The session answer shows each draft's split (at and ways) and outOfDate: true when the draft changed since it was asked. It is not shown while the repository is not in My repositories. A wrong form fails the run with "The architect's answer did not have the agreed form" and the old ways stay; a draft that is gone fails the run with a fixed sentence. The log tells split-asked and architect-split.
Size and plan review. The view of a draft also carries fit and, sometimes, planReview. Both are worked out each time the session is read, so a changed limit shows at once. Neither blocks a change of the draft or a later publish. You decide.
fitcompares the estimated files and lines withmax_filesandmax_code_linesof the repository's build flow: "likely fits in one story", or "likely too big — consider splitting" (oversaysfiles,linesor both). It names both limits. The limits come from an enabled watcher of the repository whose flow has both; the watcher'svarswin over the flow's. Your own stored watcher is looked at first, then one inconfig.yaml, then any other. Only the two numbers and the label name are shown, nothing else of the watcher. With no such watcher,fitsays the build limits are not known and gives no verdict.planReviewappears when the view has at least onesensitivetopic (sign-in, permissions, secrets, credentials or stored user data). It recommends a plan review by a person and names the topics and the repository's review label (review_plan_label). Without a known label it still recommends, and says there is no review label.PUT /api/refinement/:id/drafts/:did/review-labelwith{ "add": true }or{ "add": false }stores your choice with the draft asaddReviewLabel. Only the owner may set it, also when no review is recommended. Nothing is sent to GitHub, and no run sets it; publishing will read it.
Move to the notes. POST …/drafts/:did/move-to-notes with { "field": "…", "item": "…" } (item only for criteria) adds the text to the notes for the builder as a line "Wish: <text>" and removes it from its field. It works only for a text with a plan remark (code checks or review) or a how remark (review, not stale); otherwise it is refused. Nothing moves by itself. Typed text added to typed notes stays typed; any mix with accepted text makes the notes accepted-edited.
Ready check. POST …/drafts/:did/ready-check (no body) checks the draft against the Definition of Ready of its repository, by code only (no AI call), and answers 200 with the session. Same rules as the other draft calls: owner only (404 another user, 403 an admin), 409 for a dropped session or a repository not in My repositories, and 409 when the log has no room. The draft shows readiness: { at, items: [{ id, text, result, reason, by }] }. result is met, not-met or unsure; by is code; the reason is one sentence of at most 300 characters that names the field or text it is about. The check never changes a field of the draft.
no-open-questions: met when the map has no open question and no question waits for an answer; otherwise not met, with the count.out-of-scope: met when Out of scope has text; otherwise not met.checkable: not met with no acceptance criterion; otherwise unsure.value: not met when "As …" or "so that …" is empty; otherwise unsure.standalone: not met when a depends-on draft is gone or is the draft itself; otherwise unsure.no-plan: not met when aplanremark exists (the word found is quoted); otherwise unsure.smalland items without a rule: unsure. An unsure reason says that the architect has to judge it.
Accepted anyway. POST …/drafts/:did/ready/:item/accept with { "reason": "…" } (1 to 300 characters, required) marks an item "accepted anyway"; DELETE on the same path removes the mark. The item with the rule no-plan cannot be accepted anyway (409); an item that is not in the repository's list is 404. The reasons are stored with the draft and go into preview.body as a section ### Accepted anyway, one line per item (the item text and the reason); the section is left out when there are none. A mark counts only for the wording it was given for: after the admin rewords the item it is not shown or published, and neither is a mark for an item that is gone. A mark on an item the last check says is met stays stored, shows as "not needed" and is left out of the preview.
Ready. A draft is ready when it has a check and every item of the repository's current list is met or accepted anyway; otherwise its state is drafting. An item that is new or reworded after the check counts as not checked. The session state is ready when it has at least one draft and every draft is ready, and goes back to drafting when any draft is not. The draft state is the truth; the session state is a summary. Any change of a draft's text, a move to the notes, an accepted suggestion, a removed draft it depended on, a change of the open questions or an Epic change that alters the preview removes the check results (of that draft, or of every draft for the last two) and makes it drafting again. The accepted-anyway reasons stay. The stored session state is corrected when the session is read, for example after the admin changed the list; publishing must call isReady again and not trust the stored state.
Log. The log tells that a readiness check was made (with the counts), that an item was accepted anyway and that a mark was removed. A check and an accept need room in the log. It also tells that a review was asked for, that the architect reviewed (with the number of remarks), and that a text was moved to the notes.
Remarks on the page. Under a field or a criterion the page shows the remarks about that text. They are plain text, never HTML.
- The remarks of the code checks show after each save, with the word that was found (for example: "fast" is vague — say what can be observed). They update by themselves; the field you are typing in is not redrawn, so its text and cursor stay.
- Review draft asks the architect for a review. It shows when the session has a brief and the draft has some text (otherwise the page says to write something first). While the architect works a line says so and the button is gone; a paused run shows the reason and Ask again, a failed one Try again. It saves unsaved text first and sends nothing if that save fails.
- The architect's remarks show next to their field or criterion, with the kind in words: "Cannot be checked", "Vague", "Contradicts", "Describes how to build" and "An implementation plan". A remark about a text that changed after the review says "written before your last change". The page says when the review was made. Remarks about a criterion that is gone show once, under the criteria.
- A plan or how-to-build remark says "This belongs in the build step." and has Move to notes for the builder. The page asks first ("Move this text to the notes for the builder? It is taken out of its field."). After you confirm, the text is added to the notes as a "Wish:" line and the page shows it. A stale review remark has no button. Text you typed in other fields and have not saved is saved first and stays.
- No text in any field changes unless you type or press a button. Remarks and buttons show only where the fields of the draft show; elsewhere (dropped session, admin, missing repository) the remarks show as text without buttons.
- The log tells a review asked for, a review made and a text moved. The Context brief part does not show the line of a review run. A review run for a draft that is not open shows its line at the top of Story drafts, like a suggestion run.
The architect's view on the page. Every open draft has a part Architect's view with the button Ask for the architect's view. It shows when the session has a brief and the draft has some text; otherwise the page says to write something first. While the architect works the page shows the same status line as the other architect runs; a paused run shows its reason with Ask again, a failed one Try again. Unsaved text is saved first; if that save fails, nothing is asked.
- The view shows the areas with their files, what the draft depends on, what depends on it, the risks by kind (data, security, compatibility, users) with one sentence each, the size (small, medium or large) with the estimated files and lines, and the sentence that compares the size with the build limits.
- It lists the other open stories and drafts that touch the same code. For code the Foundry found, it says they cannot be built at the same time. For an estimate it says "May touch the same code — likely cannot be built at the same time."
- Every statement is marked found in the code or estimate. The size and the fit sentence are always estimates. The page never shows hours or days.
- When a plan review is recommended, the page says why and shows the checkbox Add the review label when this story is published, with the label name. It is off until you tick it. The choice is only kept with the draft; nothing is sent to GitHub.
- A view written before your last change shows out of date with Ask again. The notes for the builder count as a change, because the architect reads them.
- The view is advice. It has no button that changes a field, and nothing on the page is disabled because of it.
- Where the fields of the draft are not shown (another account's session as an admin, a dropped session) the view shows as text without buttons; a ticked review label shows as a sentence.
- The log tells
impact-askedandarchitect-impactin words.
Readiness on the page. Every open draft has a part Definition of Ready, with the state of the draft next to the title: Ready or Drafting. The list of drafts and the session show the same.
- It lists the items of the repository's list in order. Each has Met, Not met, Unsure or Not checked yet, its one-sentence reason, and whether it was checked by code or judged by the architect. The page says when the check was made, and says so when the list changed after it.
- Check readiness saves unsaved text first (and checks nothing if that save fails), then asks for the check. When the architect has to judge items, a line says it is at work; a paused run shows its reason and Ask again, a failed one Try again, like Review draft. The architect needs a context brief only for the unsure items; if there is none, the page says to ask for one first. The code results show anyway.
- Every item that is not met or unsure has Accept anyway. A dialog asks for a reason (up to 300 characters); it cannot be empty. An accepted item shows its reason and Remove reason, which asks first. The item about an implementation plan has no such button; the page says a plan belongs in the build step.
- After you change a field, the check results are gone and the draft shows Drafting. The reasons accepted anyway stay.
- The preview shows the section Accepted anyway as the server wrote it.
- The part and its buttons show only where the draft fields show. Elsewhere (another account's session as an admin, a dropped session) the results show as text without buttons.
- The log tells a check asked for, the architect's judgement, an item accepted anyway and a reason removed, in words. The Context brief part does not show the line of a readiness run. A readiness run for a draft that is not open shows its line at the top of Story drafts.
Publishing. POST /api/refinement/:id/publish creates GitHub issues for the ready drafts, with the repository's sign-in. The body is optional: { "drafts": [ { "id": "<draft id>", "labels": ["…"], "startBuilding": false } ] }. Without drafts, every ready draft is created with no extra labels. Only the owner may publish (an admin who is not the owner: 403). The answer lists the issues it made or found, with numbers and links.
- Order and numbers. A draft is created after the drafts it depends on, so its "Depends on" lines use the real issue numbers (
- #101), not "new issue". A draft that has an issue is never created again. - Split originals. A draft that was split gets no issue and is never marked published; its parts are published instead. A draft that depended on the original is created after all its parts and names each part's issue. The session is published when every draft that is not a split original is on GitHub. The answer has
leftBehind: [{ draft, title, criteria }]for split originals that still hold criteria, like the plan (also when nothing is left to create); the key is absent when there are none. A part that is on GitHub cannot be split again, removed, or lose a criterion by a move (409), so the same criteria never get a second issue. - Labels. Chosen labels must exist in the repository and are sent in its spelling. The build label is added only when
startBuildingis true, and needs a watcher on the repository (else 400). The review label is added only for a draft with the review label choice on. You cannot choose the build or review label by hand (400). One unknown label refuses the whole call before anything is created. - Title. A draft needs a title. If a ready draft has none, the call is refused (409) and nothing is created.
- The hidden marker. Each issue body ends with a hidden line naming the session and the draft. If a call fails halfway, publish again: drafts that have an issue are skipped, and an issue made before the answer was lost is found by its marker and taken over, with its text and labels unchanged. After a timeout, wait a moment before you try again: GitHub's list of issues can lag a few seconds, and an issue not listed yet would be created twice. Only the newest 100 issues are searched.
- While it runs. The session cannot be changed while it is being published (409, "try again in a moment"); this includes rename, drop and architect calls. Publish waits (409) while an architect run of the session is queued or running; a paused run does not block it. A second publish at the same time gets 409. A session whose log is full cannot be published.
- Replacing a split issue. When the session came from an issue and that issue was split, the issue is replaced once every part is on GitHub. Until then only the ready parts are created, and nothing is written to the original or to issues that depend on it. Then, in this order: (1) each open issue that lists the original under "Depends on" gets the parts in its place (only that list changes, never the title) and a comment with the text before and after; an issue that names the original only by title gets a comment asking you to change it by hand; (2) every trigger label of an issues watcher is taken off the original, so the Foundry does not build it; (3) the original gets one comment that names the parts, any criteria left behind, and says it will be closed; (4) the original is read again and closed as not planned, so the backlog holds only the parts. The answer has
replaced: { issue, parts, dependants, closed, closedAt? }, whereclosedisnot_planned(withclosedAt),otheroropen. The original is not closed, and its comment says it stays open, when the repository has more than 1,000 open issues and pull requests, when a dependant had to be changed or checked by hand (it may still depend on the original, and a closed issue counts as done), or when it is a story the monitor opened (closing it would mute the finding): check it and close it by hand (closed: "open"). An original closed in another way is left so (closed: "other"). If it started to be built before the close, the answer is 409 and the replacement stays due. Closing can be undone on GitHub by reopening. Sessions finished before this change with the original open stay done and are not closed afterwards. A closed original, or one the Foundry builds, is refused (409) before anything is written, unless the replacement had started already. If a call fails, publish again (with{}if nothing is left to create); nothing is written twice. An edit made on GitHub inside the "Depends on" list while it is read gives 409; publish again. GitHub cannot refuse an out-of-date update, so an edit made in the moment between the last read and the update can be lost. While the replacement is due, the issue cannot be imported again, and the split mark draft cannot be removed once a part is on GitHub. - Afterwards. A published draft shows
published: { issue, url, at }and the log hasdraft-published. It cannot be changed any more: edits, ready checks, the review label, suggestions and architect calls on it give 409 naming the issue. While a draft is published, the Epic cannot be changed, a map entry that the draft is tied to cannot be removed, and a draft that a published draft still names cannot be removed. Other drafts work as before. Editing after publishing comes later.
Publishing on the session page. The session page shows Publish only to the owner, while the repository is in My repositories, and only when at least one draft is ready and not on GitHub yet, or when the replacement of a split issue is not finished (also in a Published session). An admin who is not the owner does not see it.
Save first. Text you typed in a draft is saved before the plan is shown. If it cannot be saved, nothing is published. If some text has no place on the page any more, you are asked whether to publish anyway.
The plan. Publish opens a window with the issues in the order they will be created. Each shows its title, text, dependencies (
#12, or "new issue 2: Title") and labels. Drafts that are not ready are listed with the reason and are not published. Nothing is sent to GitHub until you press Create the issues.Labels. For each draft you tick labels from the labels of the repository. Nothing is ticked for you, except the review label when the draft asked for it. The build and review labels are not in the list; they are set by the rules.
Start building this story. Each draft has this tick box, off by default. It names the build label. If the repository has no enabled watcher for issues, the box is not shown and a short sentence says why. If the build label does not exist in the repository, the box is off and cannot be ticked.
The issue changed on GitHub. In a session that came from an issue, Create the issues first reads the issue again. When its title or text is not what the session remembered, nothing is written. The window then shows both versions side by side: the title and text on GitHub now, and the title and text the Foundry would write. Line ends and white space around the text are ignored; a change of labels or comments alone does not ask. Choose one:
- Keep mine publishes your version and replaces the text on GitHub. The GitHub version you saw is the one kept, folded, in the comment. If GitHub changed again after you saw it, you are asked again with the newer versions.
- Keep GitHub's writes nothing to the issue and publishes none of the listed stories. The session remembers the GitHub version as its source, so it does not ask again, and the draft stays unpublished: go on editing or drop the session. It is refused (409) while an unfinished update is pending, so the old text is not lost.
The publish plan shows the same state as
changedOnGithubbefore you press the button.Replacing a split issue. When the session came from an issue that was split, the window says so. Once every part is on GitHub, it says
Issue #N is replaced by its parts and closed as not planned.or, when the issue stays open (see above), that it gets the comment but stays open and should be checked and closed by hand; before that it says that nothing changes for it now. Under "Issues that depend on #N" it lists each open issue that names the issue under "Depends on", with the text Before and After; an issue that names it only by its title shows "Change by hand: it names the issue by its title." and gets a comment instead. Publishing rewrites the dependants and comments on them, and comments on the original with the names of the parts, then closes it as not planned. If criteria were left behind on it, the comment names them. If the repository has more than 1,000 open issues and pull requests, the window warns that some issues that depend on the original may be missing. The button reads Replace the issue when nothing is created, and Create the issues and replace the original when something is. The session page says how far it is: waiting for the parts, "not replaced yet" (Publish is offered again: publish again to finish), or "was replaced by #a, #b", followed by nothing more (closed as not planned), "It was closed on GitHub in another way and is left so.", or "It is still open: check it and close it by hand." The message after publishing saysissue #N is replaced,issue #N is replaced; it was closed in another way, orissue #N is not closed: check and close it by hand. Dropping the session, or removing the split original before any part is published, gives the replacement up. Titles and texts from GitHub are shown as plain text.After publishing. Each published draft shows On GitHub: #n with a link to its issue, and its fields are read only. The session shows Published when every draft is on GitHub.
After a failure. The page shows the message of the server and which drafts are on GitHub already. Publish is offered again for the rest; drafts that are on GitHub are not created twice.
Depends on. Each item is { "issue": n } (a whole number from 1) or { "draft": "<id>" } (another draft of this session). A draft cannot depend on itself, and the same item cannot be in the list twice. Issue numbers are not checked against GitHub yet.
The preview. Every draft in the session has preview: { title, body }, the story as Markdown. It is only your text and fixed words; show it as text. For example:
**Epic:** #73
As an admin, I want to export a report, so that I can share it.
### Acceptance criteria
- [ ] It downloads
### Out of scope
PDF
### Notes for the builder
Use the old API
### Depends on
- #12
- Sign in (draft)
An empty part shows as "…"; a full stop is added when the why has none; "Out of scope" and "Notes for the builder" show only with text; with nothing to depend on, "Depends on" says "None (can be built on its own)."
Who may do what. Only the owner changes drafts and the Epic. Another user gets 404, an admin 403 (an admin may read), a dropped session or a repository that is not in My repositories 409. While the repository is not in My repositories the drafts are not shown (draftsHidden: true).
What is logged. Adding and removing a draft and setting or clearing the Epic. Saving text writes no line. Drafts and the Epic are kept in refinements.json like the talk.
Splitting a draft#
A draft with at least 2 acceptance criteria has a Split button. It asks the architect for up to 3 ways to cut the story into smaller drafts. It shows the run like the other asks: queued, running, paused (with Ask again) or failed (with the reason). Nothing is split and no field changes until you press Confirm split.
The ways. Each way shows:
- its cut in words (by step, by interface, by data, by rule, or "learn first (spike)");
- the stories in order, each with its sentence, its criteria and what it depends on;
- what the first story already delivers;
- the criteria that fit nowhere;
- its warnings: a story that delivers nothing a user can see or check, and two stories that touch the same code.
When the draft changed after the ways were asked, the box says "out of date" and offers Ask again.
Describe my own way. Write a short text and press Ask with my way. The architect is asked again, and its first way works out your description.
The plan. Use this way opens the plan; Start from an empty plan opens a plan with no parts. In the plan you can:
- rename parts, add parts and remove parts;
- move a criterion to another part, or to Fits nowhere;
- change the order of the parts (Up, Down);
- set Depends on for a part.
The plan is kept in the page only, so reloading the page loses it. Discard plan drops it.
Problems are shown before sending. The plan names a criterion that is in no list, a part that depends on a later part, a part without a title and fewer than 2 parts. Confirm split stays off until the plan is right, and its text says how many drafts it creates. If you type a criterion just before you confirm, the page saves it first and shows it under "In no list" instead of sending.
After Confirm split. Each part becomes a new draft, the page opens the first one, and the original stays as a read-only record (see "Moving a criterion between the parts of a split" for moving criteria later).
Who sees it. Only people who can edit drafts see the buttons. In "View as user" no button is shown and no changing call leaves the browser; the ways are shown as text.
After the split: parts, moving and merging#
The original. It shows Split into … with a button for each part, and it is read-only. Criteria that fit nowhere are listed under Fits nowhere; each has Move to … with the parts. In the session, the original has the state word Split and does not count for "ready".
A part. It shows Part n of m of … with a link back to the original. Below it:
- the hint sentence, marked as a hint from the architect and not part of the story;
- its warnings: "delivers nothing a user can see or check" and "touches the same code as …; build one after the other".
Move a criterion. Each criterion of a part has Move to … with the other parts and the original. Text you typed in the draft is saved first. The criterion moves, it is not copied.
Depends on. The list of a part does not offer later parts of the same split, or the original.
Merge with …. A draft lists the other drafts of the session (not a split original). The page asks you to confirm and says what happens to the fields: dependencies are repointed or removed, accepted-anyway marks and readiness are cleared, and the draft gets the review label. A merge is blocked while the other draft has unsaved text.
Log. The log says "criterion moved" and "drafts merged" in plain words. Dependencies that no longer fit the split are listed when they are removed.
The talk: questions, answers and the map#
A session keeps the talk with the architect, so it is not lost. The session page shows it in two parts, Questions and Map, right after the Context brief. The calls below are what the page uses (see also "Rounds and questions from a session" below).
How a round goes on the page.
- Press Ask the architect for questions. Without a brief the page says to ask the architect to look at the code first.
- Each question shows its point of view (the user's need, the build or the test), the question, why it matters, and 2–4 options with their trade-offs. The recommended option is marked.
- Answer each question: press Choose on an option, type your own answer and press Send my answer, or press I don't know yet. An answered question shows your answer and has no buttons.
- When every question is answered, Ask for another round shows. The architect then reads your answers, proposes entries for the map and asks what is still open. If it has nothing important left to ask, the page shows its sentence; you can still ask for another round.
- In Map, proposed entries show with Accept and Reject. Entries of the map have Edit and Remove.
- When open questions remain, the page says so: "1 open question — a story with open questions is not ready". With none, there is no such line.
A question of your own. Type it in Ask the architect a question and press Send my question. Your question and the architect's answer stay on the page.
While the architect works. The page says what it is doing (reading the code, writing its questions, answering your question) and looks again every 5 seconds. No ask buttons show meanwhile. A paused or failed run shows the reason, and Ask again or Try again for that kind of run. If a call fails, the page shows the server's sentence and loads the session again; the Edit dialog closes after a failed save.
Who sees buttons. Buttons and fields show only on your own, open session, whose repository is in My repositories. A dropped session and an admin looking at another account's session show the texts without buttons. If the repository is not in My repositories, the page says that the talk is not shown. The log tells every question, answer and entry in words.
What is kept. Rounds of questions (at most 5 per round), your answer to each question, proposed entries that wait for you, and the map with three lists: rules (what must be true), examples (concrete cases, including edge cases) and open questions. GET /api/refinement/:id returns all of it as talk. The log has every question, every answer, and every accepted, rejected, changed and removed entry, with its text (cut at 2,000 characters).
Three kinds of answer. POST /api/refinement/:id/questions/:qid/answer takes { "option": n } (an option of the question, counted from 1), { "text": "…" } (your own answer, 1–2,000 characters) or { "unknown": true } ("I don't know yet"). A question is answered once; a second answer gets 409. "I don't know yet" puts the question in the open questions at once.
Accept and reject. A proposed entry waits. Accept (POST …/proposals/:pid/accept) puts it in its list; Reject (POST …/proposals/:pid/reject) removes it. Nothing is in the map that you did not accept, apart from the open questions that came from "I don't know yet".
Change and remove. PUT /api/refinement/:id/map/:eid with { "text": "…" } (1–500 characters) changes an entry; DELETE /api/refinement/:id/map/:eid removes it.
Who may do what. Only the owner changes the talk. Another user gets 404, an admin 403 (an admin may read it). A dropped session answers 409.
Hidden talk. While the repository is not in My repositories, the talk and the texts of its log lines are not shown (talkHidden: true), and the calls that change it answer 409. It comes back when you add the repository again.
Where it is kept. In refinements.json in the data folder (mode 0600). It survives a restart and is copied unchanged when the data folder moves. If the file cannot be read, the calls answer "the refinement sessions are not working; see the server log", and an account cannot be deleted until the file is repaired.
Rounds and questions from a session. Two calls, both for the owner only (another user gets 404, an admin 403; a dropped session or a repository that is not in My repositories gets 409). Both answer 202 with the session, and its architect part has kind: brief, round or question.
POST /api/refinement/:id/roundasks the architect for a round of questions. It needs a context brief ("ask the architect to look at the code first") and an answer to every question of the last round ("answer every question of the last round first; "I don't know yet" is an answer"). You can ask for as many rounds as you like.POST /api/refinement/:id/askwith{ "question": "…" }(1–2,000 characters) asks the architect a question of your own. It needs no brief. The question is logged when the run starts.
What the architect gets. The talk so far as the task: your idea, the brief, the map, every round with its questions and your answers (the answers of the last round are marked as new) and the entries you rejected. It is at most 90,000 bytes. When it is longer, the oldest rounds are left out first, then the brief is cut, then the end; the text says what was left out. The question of your own always stays whole.
What is stored. When the run succeeds, a round is stored as a new round (at most 5 questions), its proposals wait for you, and the done sentence is kept when the architect has nothing important left; the log says so (round-started, question, round-done, architect-round). An answer is stored with your question and logged (architect-answered). A failed or cancelled run changes nothing in the talk; the session says why in plain words.
One at a time. A session has one architect run at a time, counted together with the brief read (409 with a plain sentence). You can ask the architect in several sessions: the runs of one account wait in line and the architect works on them one after another, in the order they were asked. A waiting session says how many of your other sessions are first. An architect run takes none of the Foundry's run places (concurrency) and is not held back by a helper's cap such as the load governor: it starts at once, unless another architect run of your account works. A paused run is resumed by the same call, in the same run; a call for another kind gets 409 and says which run is paused. Dropping the session or deleting the account cancels the run. The log keeps free the lines the end of the run needs, so other changes may be refused with "the log of this session is full" while it runs. At most 50 own questions are kept.
What you see of the run. It shows in your Runs list with the mark "refinement", and nowhere else. Its task is shown as one line (the first line of the talk) in the Runs list, on the run page and in the queue.
The architect's context brief#
The flow refine-brief lets the architect read a repository and its open issues and write a context brief for an idea, so that refining starts from the code and the backlog instead of guesses. You can run it by hand:
scf run refine-brief --task "your idea" --var github_repo=owner/name
From a session. On the session page, the Context brief part has the button Ask the architect to look at the code. Only the owner of an open session sees it, and not when the repository is not in My repositories any more. While the architect is queued or running, the page says so and what it is doing, updates itself every 5 seconds until the read ends, and has no button. A paused read says why (usage limit, signed out, daily budget) and has Ask again. A failed read says why in plain words and has Try again. With a brief the button is Refresh; the old brief stays on the page until the new one is done. The brief shows its five parts, when it was made and which branch was read, as plain text. The page shows no costs, models or folders. The button calls POST /api/refinement/:id/architect; no flow needs to be published. The server starts the read for the idea, on the session's repository, and the session shows its state: idle, queued, running (with what it is doing), paused or failed (with the reason in plain words). When the read succeeds, the brief is kept with the session (text, time, branch and run id). Asking again refreshes it; the old brief stays until the new read has succeeded, and a failed or cancelled read leaves it as it was. A read paused by a usage limit, a sign-out or the daily budget is resumed by asking again. There is one read per session at a time (a second ask for the same session answers 409). A read asked for while the architect works for another of your sessions waits in line and starts by itself; you do not have to come back to ask again. A read costs at most $3 and counts for the daily budget. The read is in the Runs list, marked with its session, and in the costs and statistics; it is not on the board, in Your turn or in notifications, and a failure shows in the session only. Drop a session and its read is cancelled, also a paused one. An architect run is continued from its session only, not from the Runs page. While the repository is not in My repositories, the session does not show the brief; it comes back with the repository.
What it reads. It clones the repository (the develop branch when the remote has one, the default branch otherwise) and reads the open issues with all their comments. Up to 200 open issues are read, the newest first. A body is cut at 2,000 characters and a comment at 600; the cut is marked. When the backlog is larger than 200, the brief must say so under "Could not find out", or the run fails.
The five parts. Each has its own heading, in this order: What already exists, Code the idea would touch, Open issues that overlap, Rules that apply (from CLAUDE.md, the README and architecture documents) and Could not find out. Every claim about the code names its file; every claim about the backlog names its issue number. A brief that misses a part, leaves one empty, puts the headings in another order or holds a code block fails the run. A part with nothing says "Nothing found."
It only reads. The architect has the tools Read, Glob and Grep and nothing else. No step pushes, comments, labels or changes anything on GitHub. The repository is cloned into a subfolder, so its own .claude/ settings and hooks are not loaded. Your idea and the issue text are never put into a shell command, and the architect treats them as text to read, never as instructions. Its role is written once, in the block Architect (charter): it asks, explains, warns and suggests; it never decides, never writes a plan or code, and says "I don't know" instead of guessing.
Whose access it uses. In a run the server started for a refinement session, the clone and the issue list use the sign-in you stored for the repository under My repositories (its token, its deploy key or the GitHub App), and nothing else (not the server's gh login, not the bot token). A token needs read access to Contents and Issues. A deploy key gives git access only, so the issue list fails for such a repository; choose a token or the app. The architect and every other step never get it. For a repository with the method "none" the server's own access is used, but only when the owner of the run is an admin; any other account gets "set a token for this repository under My repositories". A token that is missing, cannot be read or is refused by GitHub fails the run with a sentence in plain words. Runs started by hand, by the CLI or by a watcher use the stored token too, in their marked steps. For admins: with a stored token the clone ignores the server's git settings and allows only https, so a proxy or an own CA must be set in the server's environment (HTTPS_PROXY, GIT_SSL_CAINFO).
Cost and model. One run costs at most $3. It uses the planning model of the build flow (claude-opus-5-5); an admin changes it with a routing rule for the flow refine-brief on the Models page.
Cannot be deleted. Refinement uses the flow, so DELETE /api/flows/refine-brief is refused (also for a copy an admin saved).
The architect's question round#
The flow refine-round lets the architect ask the questions a good team would ask in refinement, or answer a question of yours. You can run it by hand, or start it from a refinement session (see "Rounds and questions from a session" above). Give it the talk so far as the task:
scf run refine-round --task "<the talk so far>" --var github_repo=owner/name [--var ask=question] [--var ask=suggest --var field=…] [--var ask=review] [--var ask=impact] [--var ask=split]
What it reads. The code of the repository (the develop branch when there is one, else the default branch). Only for ask=impact the step list_issues also reads the newest 50 open issues (titles, texts and labels, no comments) into issues.md; for every other ask it reads nothing and prints one line saying so. Then the open issues are not read: what the talk says about the backlog is what the architect knows of it.
ask=round (the default). The answer is one JSON object. questions has at most 5 entries, the most important first. Each has a view (need, build or test), a text, a why, 2 to 4 options (each with a text and a tradeoff) and recommended, the position of the recommended option counted from 1. In the first round there is at least one question from each view. proposals has at most 20 entries for the lists of the story: a list (rule, example or open) and a text, from the answers the talk marks as new. done is one sentence; it is required when there are no questions, because the architect has nothing important left to ask.
ask=question. The answer is { "answer": "…" }, with no questions and no proposals. Every claim about the code names its file.
ask=suggest. Run with --var field=title|who|what|why|criteria|outOfScope|dependsOn|notes. The answer is { "suggestions": [ … ] }: { "text": "…" } for a text field (one), { "text": "…", "from": "R1" } for criteria (up to 10; from is a rule or example number of the task) and { "issue": 12 } or { "draft": "D1" } for depends on (up to 10; other items are left out). No questions and no proposals; never an implementation plan. The check prints { "field": …, "suggestions": [ … ] }. Texts are cut at title 120 (on one line), who, what, why and criterion 500, out of scope and notes 5,000 characters. It fails with one plain sentence, without text of the answer, for questions or proposals, a suggestions that is not a list, an item that is not an object or has no text, a criterion without a rule or example number, an unknown field, or an ask that is not round, question, suggest or review.
ask=review. The answer is { "remarks": [ … ] }. Each remark is { "field": "…", "item": "C1", "kind": "…", "text": "…" }: field is title, who, what, why, criteria or outOfScope; item (a criterion number) only for criteria; kind is uncheckable, vague, contradiction, how or plan. The architect only points out: no questions, no proposals, no new text and no plan. The check prints { "remarks": [ … ] }: the first 20, each text on one line, cut at 300 characters, in at most two sentences (more fails with one plain sentence, without text of the answer).
ask=impact. The architect says what a draft touches, how risky it is and how big it is. The answer is one JSON object; every statement has a basis, found (read in a file or an issue) or estimate:
areas(at most 15):{ area, files, basis, why }.areais a directory or file path, as in theAREAS:line of a build plan;filesare at most 8 files read. An area markedfoundwithout a file becomesestimate.dependsOnanddependents(at most 10 each):{ issue }or{ draft: "D1" }, withbasisandwhy.risks(at most 12):{ kind, basis, text }.kindisdata,security,compatibilityorusers;textis one sentence.size:{ size, files, lines, why }.filesis the number of files changed (all files);linesis the lines of new or changed production code (tests and docs do not count). Both are whole-number estimates.sizeissmall(at most 5 files and 200 lines),large(more than 15 files or 800 lines) ormedium; the check sets the word from the numbers.overlaps(at most 20):{ issue, areas, basis, why }, an open issue that touches the same areas. The issue must be inissues.mdand the areas must be among the answer's areas. An overlap names an issue ({ issue }) or another draft ({ draft: "D2" }). The server, not the architect, sets itsbasis:foundonly when the issue or draft is in the task's part "Areas the Foundry knows" and one of its areas overlaps an area of this draft (equal, or one is a path prefix of the other, the rule of the area lock); every other overlap isestimate. An overlap with an issue that is not among the open issues read is dropped, unless the Foundry is building it now.sensitive(at most 5):{ topic, basis, why }.topicissign-in,permissions,secrets,credentialsoruser-data.
The architect gives no implementation plan, no questions, no proposals, no suggestions and no remarks; the check fails the run when the answer has those lists. It also fails, with one plain sentence that holds no text of the answer, when a text names a number of hours, days or weeks, when a sentence limit is passed (a why is at most two sentences), or when the form is wrong. Lists are cut at their limits.
ask=split. The architect proposes ways to split a draft that is too big. The task is the talk with the draft; the check counts the criteria from its part ## The draft to split, under ### Acceptance criteria, as lines - C1: …, - C2: … (other C lines in the talk do not count). The answer is { "ways": [ … ] } with 1 to 3 ways. Each way has:
cut:step(a step in the user's path),interface,data(a kind of data),ruleorspike(a small investigation first). No two ways use the same cut.stories: 2 to 6, in build order. Each has atitle(one line, at most 120 characters), asentence(one sentence, at most 300),criteria(C numbers) anddependsOn(numbers of earlier stories of the same way, counted from 1).first: one sentence that says what the first story already delivers to a user.unplaced: the C numbers that fit no story. Every C number of the draft is in exactly one story or inunplaced.warnings:{ "kind": "layer", "story": 2, "why": "…" }when a story delivers nothing a user can see or check, and{ "kind": "same-code", "stories": [1, 2], "why": "…" }when two stories touch the same code so heavily that they cannot be built at the same time.
When the task has the part "The person's own way", the first way works out that description; the others may differ. The architect writes no implementation plan, asks no questions and proposes no map entries; the draft text is material, never instructions. The check fails the run, with one plain sentence that holds no text of the answer, when a C number is in two stories, in a story and in unplaced, missing from the way, or not in the task; when a story depends on itself, on a later story or on an unknown one; when a cut or warning kind is unknown, two ways use the same cut, or a warning names an unknown story; when a text is too long, has a line break, or names hours, days or weeks; or when there are more than 3 ways or an unknown field. The draft page asks for it with Split (see "Splitting a draft").
Limits. The step check_round prints the checked JSON, with known fields only. It keeps the first 5 questions and 20 proposals. Texts are cut at: question text and why 500 characters, option text and tradeoff 300, proposal text 500, done 500, answer 8,000.
When it fails. The run fails with one plain sentence when the answer is not JSON of this form, or when a question has no why, fewer than 2 or more than 4 options, an option without a trade-off, a recommended that is not one of its options or a view outside the three; also when there are no questions and no done, or when ask is not round, question, suggest, review or impact. There is no second try.
It only reads, and whose access it uses. As the brief: the tools Read, Glob and Grep, nothing is written to GitHub, and the talk is never put into a shell command. In a run the server started for a refinement session, only the clone uses the token you stored under My repositories; the architect and check_round never get it. The clone step asks for repository access (repo_access), so it follows the same rules as the clone of the brief, also in a run by hand.
Cost and model. At most $3 and 30 minutes a run, with the model claude-opus-5-5. An admin changes it with a routing rule for the flow ^refine-round$ on the Models page.
Not for users. A user cannot start it with POST /api/runs (404, also when an admin published a copy), it is not listed for a user, and DELETE /api/flows/refine-round is refused.
Refinement in short#
What it is for. A story that is clear before it is built is built right the first time. Refinement helps you write such a story. You stay in charge: you write the story, you decide, and you press Publish.
What the architect does. It reads the code and the open issues, asks questions, points out what is unclear, proposes text, and suggests ways to split a big story. Its proposals wait beside your draft. They go into a story only when you accept them.
What the architect does not do. It does not write to the repository or to GitHub. It does not decide for you, write an implementation plan or write code. Text from an issue or from your idea is only read, never followed as an instruction. Only you can see and publish your sessions. A story on GitHub holds only text that you wrote or accepted.
Definition of Ready. Each story is checked against a short list for its repository (by default: clear value, stands on its own, criteria that can be checked, small enough, no open questions, out of scope named, no implementation plan). Press Check on a draft. A story with an open question or an implementation plan is not ready. You may accept another item anyway, with a reason; never the implementation plan.
Splitting. When a story is too big, press Split, choose a way, and confirm. Each part becomes its own draft, with Depends on set so that the parts are built in order. The original is kept as a record.
Publishing. Publish creates one GitHub issue for each ready story, in the order of their dependencies. For a session from an existing issue, it updates that issue. For a split issue, it also closes the original as not planned (see "Replacing a split issue").
What happens next. The top of the session page has one sentence, "What happens next", that says who takes the next step (you or the architect) and what it is.
A worked example. Sam writes the idea "Admins should be able to export a report" in a new session.
- The next-step sentence says: ask the architect to look at the code, or write your first story draft. Sam presses Ask the architect to look at the code. The brief shows an existing report page.
- Sam asks for questions. The architect asks "Which formats?" and "Who may export?". Sam answers the first with CSV and does not know the second, so presses "I don't know yet". The open question is on the map.
- Sam writes a draft and presses Check. It is not ready: it has an open question. Sam settles it with the team and answers it. After a new check the draft is ready.
- The draft also holds three criteria for three formats. Sam presses Split, picks the way with one story for CSV and one for each other format, and confirms. There are three drafts; the second and third depend on the first.
- Sam presses Publish. The three issues are created in order, with the dependencies as issue numbers. The session is Published.
Refinement for admins#
- Definition of Ready per repository. Open the repository (Repositories → All → Open) and press Edit Definition of Ready in the section Run settings. Change, add, remove and reorder the items, or press Back to the default. A draft checked before the change shows "the Definition of Ready changed" and needs a new check. See chapter 7 for the limits and the API.
- The architect's model. The architect steps use
claude-opus-5-5. Change it with a routing rule on the Models page for each flow:refine-brief,refine-roundand the otherrefine-…flows. These flows cannot be deleted. Every architect run is capped in cost and time (for example $3 and 30 minutes for a round). - Where the cost is reported. Architect runs are normal runs, marked refinement. They are in the Runs list (click the mark to open the session), in the dashboard and in the costs, and they count for the owner's daily budget and for "at the same time", but not for "runs per day". A user does not see amounts; an admin does. They are not on the board and not in notifications.