Friday · Build

The mechanism design system

The standard every mechanism of the Friday CLI is built to: commands, flags, keys, settings, messages, tools, sub-agent roles, protocol methods, events, files and exit codes. A visual design system fixes how things look; this one fixes how things work and how they are named, and checks it.

This documentation is in English.

On this page
  1. 1 Principles
  2. 2 Vocabulary
  3. 3 Names
  4. 4 Measures
  5. 5 Words people read
  6. 6 The catalog
  7. 7 Recipes
  8. 8 Documentation
  9. 9 Conformance
  10. 10 Interaction

It is built for precision in two senses. From Swiss typography: one grid for everything, words with one meaning, no ornament, structure visible. From Swiss watchmaking: every part made to a stated measure, every measure checked, and a tolerance of zero.

The rules are code: internal/conform. Each registry is held to them by a TestConform… test beside it, and bun run recheck runs every one of them on every run. There is no list of excused exceptions. A rule that does not fit is changed in code, in this document and in the tracker, together.

  1. Principles
  2. Vocabulary
  3. Names
  4. Measures
  5. Words people read
  6. The catalog
  7. Recipes
  8. Documentation
  9. Conformance
  10. Interaction

1 Principles

#PrincipleIn practice
1.1One table per mechanism.Every slash command is a row of commands; every key a row of actions; every tool an entry of Builtins(); every protocol method a row of methods. Dispatch, completion, help, the docs check and the conformance test all read the same table, so what is shown is what works.
1.2It explains itself.A name and its one line say what happens, to someone who has not read the docs. No line refers to another ("The same", "As above").
1.3One meaning per word.A word in the vocabulary means one thing everywhere: interface, engines, protocol, docs.
1.4Same behaviour on every surface.A mode, an approval, a tool's arguments, an event's JSON mean the same on the Go engine and the TypeScript engine, in the interface and in an editor.
1.5Nothing is dropped silently.A flag, setting, rule or limit that cannot be honoured is refused, or the session goes where it can be (another engine), with the reason. It is never ignored.
1.6Measured, not felt.Lengths, limits, codes and timeouts are numbers, written down here, and held by a check.
1.7Checked, not remembered.Every rule in sections 3–6 names the test that enforces it. A rule with no check is a wish, and is marked as one.

2 Vocabulary

WordMeansNot
sessionone conversation in one folder, with its history, saved as it goeschat, thread (for the whole)
turnone request and all the work it causes, until the replyrun (for the person's view)
stepone model call and the tool calls it makes, inside a turniteration (in words for people)
tool callthe model asking for one tool with argumentsaction, function call
approvalthe person's answer to "Allow this?"permission prompt (in words for people)
modehow much Friday may do alone: plan, build, auto, defenderpermission level, policy
enginewhat runs a session behind the interface: the Go engine (default) or the TypeScript engineagent (for the engine), backend
providerwho serves the model (Anthropic, Groq, OpenRouter…)vendor, backend
modelwhich model of a provider: the main one, and the small one for cheap workLLM (in words for people)
sub-agenta helper the main conversation starts for part of a task, with a role; in prose for people, "helper" glosses itworker, child agent
threada sub-agent's conversation inside a session, kept on disk(never the whole session)
backgrounda sub-agent that keeps working while the turn goes onasync, detached
steeringwhat the person types while a turn runs, read at its next stepinterrupt
compactionreplacing the earlier conversation with a summarytruncation (which is cutting a result)
wallpaperthe picture behind the whole screenbackground (which is the colour)
settinga value in settings.json, also readable from the environmentconfig, option, preference
windowan app on the desktop: a frame of frosted glass with a tab in the top bar, switched to and frommodal (for a window)
dialoga question that must be answered before anything else: an approval, a confirmation, connecting a providerpopup
barsthe top bar's tabs and the dock's apps, walked as one row by keyboardtaskbar

3 Names

Every name has the grammar of its kind, checked by conform.Name.

KindGrammarExamplesChecked by
slash command^[a-z][a-z0-9-]{0,19}$/subagents, /goal-checkTestConformSlashCommands
session commandthe same as a slash commandtodos, compactTestConformSessionCommands
key actionlower-case words joined by -next-windowTestConformKeyActions
toollower-case words joined by _read_file, wait_agentsTestConformBuiltinTools, TestConformRootTools
sub-agent role^[a-z][a-z0-9-]{0,39}$explore, db-migrationsTestConformBuiltInRoles
flag--word(-word)* or -x--no-mouse, -pTestConformHelpNamesRealFlags
protocol methodinitialize, authenticate, session/<word>, _archymedes/<path>_archymedes/session/steerTestConformMethods
eventlower-case words joined by _tool_result, steering_unreadTestConformEvents
setting / variableupper-case words joined by _; Friday's own begin ARCHYMEDES_ARCHYMEDES_ENGINE, GROQ_API_KEYTestConformEveryVariableIsDocumented

Names are unique within their kind (conform.Unique). The ARCHYMEDES_ prefix, the _archymedes/ protocol prefix and the .archymedes/ folder keep their names from before the product was called Friday, so existing settings and installs keep working; new names follow them.

4 Measures

MeasureValueWhyChecked by
help line (command, method, session command)≤ 100 charactersone row of the command list at 120 columns, beside the name and hintconform.Help
message (toast, notice)≤ 120 charactersone toastconform.Message
label (key action)≤ 24 charactersthe dock and the Keys appconform.Label
role description≤ 100 characterssent to the model beside the role on every requestconform.RoleDescription
tool description≤ 400 characters, whole sentencessent with every request; shorter is cheaperconform.ToolDescription
exit code0 done · 1 failed while running · 2 refused before startingscripts can tell a usage error from a failureTestConformExitCodes
source file≤ 800 linesone sitting to reviewthe size guard
package importsthe matrix in tooling/check/go-sections.jsonlayering is a design, not an accidentthe go-layering guard

The engine's own limits (steps, tool calls, result sizes, retries, timeouts) are in the user guide; they are constants in the code beside what they limit.

5 Words people read

Help lines, messages, labels and errors follow one voice: plain, calm, exact.

RuleExampleNotChecked by
A help line or message is a sentence: it starts with a capital, or as typed (/, !, @, $, ~, ., a digit, a formatted value)Switch to plan mode: the agent reads and proposesswitch to plan modeconform.Help, conform.Message
One line has no full stop at the end; several sentences mayNothing to copy yetNothing to copy yet.the same
It stands alone: no reference to another rowEarlier sessions in this project, newest first (same as /resume)The same: earlier sessionsthe same
Calm: no exclamation marks, no capitals for emphasis (initialisms such as JSON, HEAD are fine)Rate limited; waiting 11sRATE LIMITED!the same
Say what happened, not that something went wrongNowhere to push: this repository has no remoteError: push failedconform.Message (no Error:, Failed: openers)
A warning says what to do next, after ; or :/goal between turns; esc stops this oneCannot do that nowa review rule (a wish: not mechanically checkable)
Keys are written as pressed, in lower caseesc, ctrl+c, alt+s, shift+tabEsc, Ctrl-Cconform.Help, conform.Message, conform.DocProse
Labels are lower-case wordsnext windowNext Windowconform.Label
A tool description is written for the model: whole sentences, ending in a full stopRead a text file … offset/limit for very large ones.reads filesconform.ToolDescription
A tool's error to the model is a sentence; an argument is named as typed `command` is requiredcommand is required, Error: …conform.ToolText
A Go error value follows Go: lower case, no closing punctuation; its caller adds the contextunbalanced quote in commandUnbalanced quote in command.conform.GoError
A line the binary writes to stderr says whose it isfriday: no agent foundno agent foundTestConformErrorsToolTextAndStderr
A Settings row or choice reads as a help lineOff — save with ctrl+s (default)Off — save with Ctrl+S (default)TestConformSettingsLabels

Which channel. A toast answers what the person did a moment ago and fades (toastInfo when it worked, toastWarn when it could not, with what to do). A notice is a line in the transcript that stays (noticeFaint for bookkeeping, noticeInfo for news, noticeWarn for what needs attention, noticeError when something stopped working). An approval or a question is a dialog, never a toast.

6 The catalog

Each mechanism: where its table is, what every row must satisfy, where it is documented, and the test that holds it.

MechanismTableContractDocumented inChecked by
Invocationcmd/friday/main.go (usage), internal/cli/args.go (KnownFlags, GoOnlyFlags)the help names only flags the parser knows; every flag only the binary reads is in the help; a flag the engine cannot honour is refused; exit codes 0/1/2friday --help, READMETestConformHelpNamesRealFlags, TestConformExitCodes
Slash commandsinternal/tui/cmd_registry.go (commands)name, help line and argument hint to the grammar; unique; a handler/help, the command listTestConformSlashCommands
Argument hintsthe args of each command[optional], <placeholder>, a|b; lower-case words; at most two levels—conform.ArgHint
Key actionsinternal/tui/core_keys.go (actions)id and label to the grammar; one of five groups (Typing, Apps, Windows, Session, Reading); a default key and a binding; uniquethe Keys app (F7), Help (F8)TestConformKeyActions
Messagesevery toast and notice in internal/tuithe voice in section 5—TestConformMessages (literals, format strings, and how built ones start)
Settings and variablespackages/friday-cli/src/platform/settings.ts (SETTING_FIELDS); variables read by the Go codeevery ARCHYMEDES_* the binary reads is documented; every key it reads from settings.json is a row of Settings; each row validates its valuesConfigurationTestConformEveryVariableIsDocumented, TestConformSettingsTheBinaryReadsExist, menu-invariants.test.ts
Toolsinternal/core/tools (Builtins), internal/core/agents (rootTools)name and description to the grammar; a known capability and effect; a body; a schema whose required arguments exist and whose arguments are typed; in the tools referenceToolsTestConformBuiltinTools, TestConformRootTools, tool.Contract
Sub-agent rolesinternal/core/roles (BuiltIn)name and description to the grammar; instructions, limits and a modelSub-agentsTestConformBuiltInRoles
Protocol methodsinternal/core/server/registry.go (methods, forwarded)name to the grammar; a line saying what it does; in the protocol referenceProtocolTestConformMethods
Session commandsinternal/core/server/registry.go (sessionCommands)name and line to the grammar; a reply kind the interface renders; in the protocol referenceProtocolTestConformSessionCommands
Eventsinternal/core/loop/events.go, agents.Notice kindsname to the grammar; JSON identical to the TypeScript runtime's; in the protocol referenceProtocolTestConformEvents
Packagestooling/check/go-sections.jsoneach imports only what its row listsArchitecturethe go-layering guard
Picturesinternal/gallery (Photos)free-licensed and credited, or drawn by code; ≤ 400 px shippedCREDITS.mdTestEveryPictureIsInTheCreditsFile and the gallery tests

Files on disk. What Friday writes, and where, is fixed:

FileWhereHolds
settings.jsonconfig directorysettings (section Configuration)
state.jsonconfig directorywhat the interface remembers: the welcome was seen, the wallpaper choice, the tour drawer folded
keys.jsonconfig directorychanged key bindings only
rules.jsonconfig directory, and .archymedes/rules.json in a projectcommand rules
agents/*.mdconfig directory, and .archymedes/agents/ in a projectsub-agent roles
go-sessions/<id>/.archymedes/ in a projectGo-engine sessions (Architecture)
sessions/<id>.json.archymedes/ in a projectTypeScript-engine sessions

7 Recipes

To addDoThen
a slash commandone row in commands (cmd_registry.go): name, hint, help line, handler in the cmd_ file of its familygo test -run '^TestConform' ./internal/tui
a key actionone row in actions (core_keys.go) and a field in keyMapthe same
a flaghandle it in internal/cli/args.go (and add Go-only ones to goOnlyFlags); name it in usage with what it doesgo test -run '^TestConform' ./cmd/friday
a settinga row in SETTING_FIELDS with its choices and validation; a line in ConfigurationTestConformSettings…, menu-invariants.test.ts
a toolExtending → Add a tool, and a section in Toolsgo test -run '^TestConform' ./internal/core/...
a protocol methodone row in methods (registry.go) with its line and handler; a section in Protocolthe same
a messagem.toast or m.notice with a literal or fmt.Sprintf format in the voice of section 5TestConformMessages
a worda row in the vocabulary, if it names a new thingreview

8 Documentation

The documents are held to the same precision as the mechanisms they describe. The rules are internal/conform/docs.go; TestConformDocuments, TestConformDocumentReferences and TestConformDocumentedMeasures apply them.

RuleMeasureChecked by
One title, and a sentence under it saying what the document is forexactly one # heading, firstconform.DocStructure
Headings descend one level at a timeno ## → ####conform.DocStructure
A long page lists its sections before the first6 or more ## sections need a list of 3 or more linksconform.DocStructure
Every table row has its header's cellsequal counts (pipes in code do not count)conform.DocStructure
A sentence carries one idea≤ 40 wordsconform.DocProse
No fillernone of the words in filler (simply, just, very, in order to, etc., TODO and the like)conform.DocProse
One word per thingno word from the vocabulary's "Not" columnconform.DocProse
Keys as pressedesc, ctrl+sconform.DocProse
Every link leads somewherethe file exists; a #fragment names one of its headingsTestConformDocumentReferences
Every name in code existsa path under internal/, cmd/, docs/, packages/ or tooling/; a TestConform… test; an ARCHYMEDES_… variable some code readsTestConformDocumentReferences
Every number is the code'seach limit the documents state (steps, retries, waits, timeouts, result sizes, the context window, helpers at once) is built from the constant that holds itTestConformDocumentedMeasures

Prose rules cover the documents a person reads: the README, the package README, this standard, docs/engine/ and the gallery's credits. The continuation notes in docs/continuation/ are working records; their links and names are checked, their prose is not. Fenced code is never checked as prose, and inline code is quoted, not prose.

Writing to the rules. Lead with what a thing does, then how. Split a sentence at its second idea rather than joining with a semicolon. A list of more than four parts is a table or a list, not a sentence. Name a measure by its constant's value, then let the test hold it.

9 Conformance

bash
go test -run '^TestConform' ./...     # every conformance test, in a few seconds
bun run recheck                       # runs them on every recheck, beside the guards
  • Tolerance is zero. Every conformance test passes on every commit; there is no baseline of excused findings. When the standard was introduced (WS-38), every finding was fixed rather than excused. There were 1 help line over its measure and 20 messages: 9 ending in a full stop, 11 that gave no next step. There were also 2 flags the binary read but --help did not name, and 2 variables no document named. The documentation rules (WS-39) were met the same way. They found 33 sentences over 40 words, 4 filler words, 2 retired words and 2 long pages without contents. In the code they found 13 tool errors and 3 Go errors in the wrong case, and 2 Settings labels.
  • Changing a rule is a change to internal/conform, to this document, and to the tracker, in one commit, with the reason. The conformance tests then show everything the new rule touches.
  • A rule that cannot be checked is marked here as a review rule. If it can be made checkable later, it should be.

10 Interaction

Friday is driven like a desktop: by the arrows and by the mouse. Every surface follows one grammar, held by the components they share rather than by each surface's own code.

InputMeansWhere it is built
←↑↓→move: a row in a list, a tile in a grid, between panesinternal/tui/desk_list.go, desk_tiles.go
home, end, pgup, pgdnthe first, the last, a screenfulthe same
enteropen, or do what the selected thing doeseach surface's handle
spacelook inside without leaving: a quick look, a readerthe same
escstep out one level; from a window's top level or an empty input, out to the barscore_keyboard.go, desk_bars_focus.go
q, ctrl+w, ✕close a windowdesk_window.go
↑ on an empty inputonto the conversation's newest block; on the home screen, onto the desktop's iconschat_cursor.go, home_desktop.go
ctrl+↑, ctrl+↓earlier messagescore_keys.go
a clickselectlistView.clickRow, tileGrid.clickTile
a click on the selected thingopen it, as enter doesthe same
a click on a button, a tab or the dockact at oncedesk_window.go (hintBar)
the wheelscroll what is under the pointer, never what is hiddendesk_window.go (wheel)

Windows and dialogs. Anything browsed is a window: it floats on the wallpaper with a margin, its body frosted glass, its title and ▢ zoom and ✕ close in its top edge. A dialog is kept for a question that must be answered. A window's keys are buttons in its foot, so nothing a key does is out of reach of the mouse.

Adding a surface. A list is a listView, a grid a tileGrid, a foot a hintBar. A window implements wheel (or wheelAt for panes) and click; it draws as if its inside were the screen (within). TestConformEveryWindowTakesTheWheel finds every window in the source and holds it to the wheel.

Kept in the repository as docs/mechanisms/README.md, checked by its conformance tests · synced at af2a9b2