← Architecture map

Woodpecker v2 decisions

Decisions

D1

Tenant = wallet: one Durable Object per wallet; the sign-in is a wallet signature that the DO verifies (D47).

Tenant = wallet. One Durable Object per wallet (name chainId:address), one Harness, the pi-durable tables as today. A conversation is (wallet, conversationId).
Sign-in: the wallet signs a challenge (domain, nonce, expiry); the Worker issues a short-lived credential bound to the address; the DO accepts only its own address.

D47 · D1's note "the Worker issues a short-lived credential bound to the address" → D47 (the DO verifies the sign-in; the Worker only forwards).

D2

A conversation's agent is derived from a per-wallet root the runner keeps in its DO; the agent holds no balance and pays no gas.

A conversation's identity is derived from a per-wallet root that the runner generates and keeps in its DO storage. Formulas unchanged: keccak(root, "conversation", n), subagent and schedule slots as today.
The identity has no balance and pays no gas. Contract A, gateways, directory and Portal statistics see the same client and identity shapes as today.

D3

Service kinds in the descriptor: runner, store (now memory), model, tool; one gateway may declare several kinds.

Service kinds in the descriptor: runner (hosts conversations, derives identities, speaks to the Console), store (durable conversation storage; reusable by other services), model (chat API usable as the agent's model), tool. One gateway may have several kinds.
The Services page shows the kinds as badges.

D51a, D52a · D3 and D34 kind lists → D51a and D52a: the kinds are runner, memory, model, tool, host.

D4

The runner is a service the wallet chooses; the New conversation dialog requires one.

The runner is a service chosen by the wallet. The New conversation dialog starts with a required Runner select; without a runner in My services it refuses to create and links to Services.
Resolves "who pays for the Worker + DO": the runner's operator is paid in the runner's token.

D5

A descriptor may declare uses with bundled or client payment (deferred by D48).

A descriptor may declare uses: the services it depends on, each with payment: "bundled" (in my price, invisible to the client) or payment: "client" (the client pays it; the runner signs with the conversation identity).
Recommended default (not yet decided): metered dependencies client, the provider's own infrastructure bundled.

D6

Two token kinds: direct (one gateway's unit) and proxy (a basket of child tokens); proxy tokens are deferred (D48).

Two kinds of service token. Direct: one gateway's unit, as today. Proxy: a composite service's unit backed by a basket of child tokens, with covers(child), rate(child) (proxy units charged per 1 child unit; rate 2 means 1 tDurable costs 2 tAcmeRun) and exchange(child, amount, to).
A direct token implements the three functions as "covers nothing". Rate definition fixed 2026-10-22 after the mock found D6 and D7 inverted; D7's arithmetic is the reference.

D7

The Intent gets an explicit fund field for nested billing (deferred by D48).

The Intent gets an explicit fund field: the token the client authorized. Direct billing: fund == token. Nested billing: token = the child's token, fund = the proxy. New typehash; every gateway and the runner upgrade together.
Contract A: reserve checks the authorization of (client, identity, fund) and fund.covers(token), reserving max × rate; settle pulls actual × rate of the proxy from the client to the proxy's owner and calls exchange(token, actual, payTo) from the basket. An empty basket fails the settle; the gateway releases and does not answer.

D8

One hop only: the fund must cover the token directly.

One hop only: fund must cover token directly. A proxy of a proxy is not supported.
Depth-2 nesting (a dependency spending further on the client's behalf) would need sub-authorization on A; not in scope.

D9

The proxy owner buys child tokens and deposits them into the basket (deferred by D48).

The basket: the proxy's owner buys child tokens from each child's owner and deposits them into the proxy contract. No minting rights are granted to proxies.
Portal shows basket levels; the owner refills.

D10

wpCredit is an independent credit token, not a proxy and not a fund; ≈ wp is an exchange-rate view of caps, balances and spends.

wpCredit is not a proxy and not a fund. It is an independent credit token that exchanges with every ServiceToken (each token publishes its rate).
The ≈ wp figures in the mock are this exchange-rate view of caps, balances and spends. Purchase and exchange flows: open.

D11

The agent's model is a gateway with an agent-chat route; the runner holds no provider credentials.

The agent's model is a gateway too: a chat gateway exposes an agent-chat route (tools, tool_choice, streaming, tool messages pass through; metered by usage). The runner registers such gateways as models. No provider credentials in the runner.
Precedent: today's llm-gateway provider in the Engine (gpt-luna's lane, tLLM). The round-2 template gateways need the route.

D12

The first mock UI: three menu items, authorizations grouped per identity, caps entered inline.

Mock UI (done): three menu items (Wallet & Settings, Services, Conversations); Authorizations grouped per conversation identity with ≈ wp; caps entered inline next to the Model select and on each checked tool, one value per token, total in wp and the signature count; conversation view with the Identity card on top and one card with the tabs Authorization / Spends.
Commits ffec0aa, b375fc5, 4149420; live at https://woodpecker-console-mock.pages.dev

D13

Order of work: record the decisions, finish the mock, write the v2 documents, then rewrite the modules.

Order: record now (this file); finish the mock; write the v2 architecture documents in this repository; then rewrite every module. The current system stays as it is until then.

Decisions of 2026-10-22 (the Deploy flow in the Console)

D14

The Console deploys services itself; the Console wallet is the token owner; the v1 Portal is not merged.

The Console deploys services itself: a "Deploy a service" entry on the Services page replaces the /devportal skill and the Portal's deploy pages. No Claude Code. The Console wallet is the token owner and the paying client; there is no separate Portal wallet.
The Portal is not merged into the Console; the deploy flow is mocked on its own.

D15

Deploy prerequisites: a runner, a model and a host service (kind host, D52).

Prerequisites of a deployment: My services must hold a runner, a model and a cloud service (kind cloud: a wrapped Cloudflare account that deploys Workers, writes secrets, binds DOs, reads logs; priced per operation). Missing ones are listed with an Add link.
First cloud service: Steven's own account. Other clouds later, same kind.

D52a · D15 "kind cloud" → D52a (host); the service woodpecker@0a1b/cf keeps its name and tCloud.

D16

A deployment runs as an agent conversation on the runner, with its own agent, caps and spends.

The deployment runs as an agent conversation on the runner (model + tools), not as a fixed task. The agent asks what the skill asked (preset, service id, symbol, models, limits, mapping), calls the cloud service, deploys the token with the wallet's signatures, binds, verifies. The deployment is a conversation like any other: identity, caps, spends.
The transcript shows every tool call with its price and every signature.

D17

The upstream API key goes from the browser straight to the host service's secret store; the agent sees only its fingerprint.

The upstream API key is entered in a dedicated field above the agent conversation, outside the chat. It goes from the browser straight to the cloud service's secret store. It never enters the conversation; the agent sees only its fingerprint.
Rule carried over from the skill (never print, never pass a value).

D18

Directory rows have an Add button; a host service is listed like any other service.

Directory rows get an explicit Add (to My services) button; a cloud service appears in the directory like any service.

D19

Verify is a real paid call from the Console wallet to its own new gateway.

Verify stays a real paid call, from the Console wallet to its own new gateway.

D20

Direct services first; the bundled type is reasoned again later.

First the direct (non-bundled) service type. The bundled (proxy) type and its templates are reasoned again later.

Decisions of 2026-10-22 (bundled services, languages, architecture map)

D21

A bundled service has a proxy token and declared dependencies (deferred by D48).

A bundled service is a service with a proxy token and declared dependencies. Its first template is the runner (a Worker + a Durable Object class). A runner has no upstream API key; it depends on a store (payment: client, paid through the proxy) and on the owner's cloud compute (bundled).
Other bundled templates (composite gateways) later.

D22

Deploying a bundled service adds the proxy token and the funded basket (deferred by D48).

Deploying a bundled service adds to the direct flow: choose the template, pick the dependencies from the directory, set the proxy token's symbol and the rate per covered child token, deploy the proxy token (covers, rates), fund the basket (buy child tokens from each child's owner, paid in wpCredit at the child's published rate, then deposit into the proxy), register with uses.
D9 and D10 together: the purchase is a wpCredit exchange; no minting rights.

D23

Verify of a runner is a real one-turn conversation on it (deferred by D48).

Verify of a runner is a real one-turn conversation on the new runner: a turn paid in the proxy token plus one store commit settled through the exchange path (fund = proxy, token = the store's token, basket decreases).
The nine lines of Verify are adapted per kind.

D24

A proxy service shows its basket levels with a Refill action (deferred by D48).

A proxy service deployed by this wallet shows its basket levels (per child token) with a Refill action in My services.
Refill repeats the purchase and deposit.

D25

The Console and the architecture pages are trilingual: English, 中文, Español; identifiers never translate.

The Console and the architecture map are trilingual: English (default), 中文, Español, switch in the top bar, choice kept per browser. Identifiers never translate: service names, tool names, token symbols, addresses, hashes.

D26

The architecture map lives in this repository as one HTML page, published on its own Pages project.

An architecture map of v2 lives in this repository (docs/architecture/) as one HTML page in the format of https://woodpecker-runtime-map.pages.dev/ (boxes and edges, flow buttons, info panel, legend), published at a Pages project of its own.
It is the reference for the v2 architecture documents.

Decisions of 2026-10-22, later (Steven's review of the deploy flow)

D27

The bundled deployment is dropped from the mock.

The bundled deployment is dropped from the mock (too complex for now). Proxy tokens, runners and stores stay in the directory and the decisions (D6–D9, D21–D24) as decided-not-mocked.
The deploy page offers direct services only.

D28

A deployment runs to the end on its own; it stops only when it needs the person.

A deployment runs to the end on its own. No step-by-step Next. The agent stops only when it needs the person: a question (answered in the chat) or a wallet signature (a Sign button on the card). Errors are reported by the agent in the conversation.

D29

A service deployed by this wallet opens a management page: token, submitter, Distribute, Statistics, Verify.

My services marks the services deployed by this wallet and they open a management page: what the Developer Portal shows for a service (state, origin, token, submitter and its gas, Verify, Statistics per payer and per call, Distributions) plus Mint to an address (Distribute) and an address book. Other people's services have no management page.
Replaces the Portal's Services, Tokens, Distribute and Statistics pages for the wallet's own services; the Portal itself is not merged (D14).

Decision of 2026-10-23 (Steven's review of the self-running deploy)

D30

A deployment asks nothing in the chat; it pauses only for wallet signatures: the caps, the contracts card, the verify card.

A deployment asks the person nothing in the chat. Everything it needs is given before it starts: the prerequisites (runner, model, cloud), the upstream API key, and the service details (preset, service id, token symbol, label) in a small form with prefilled suggestions. From Deploy to done the agent runs on its own. It pauses only twice, for wallet signatures: once for the contracts (fund submitter, deploy token, setService, register in the directory, one card, one Sign that signs them in sequence) and once for verify (mint, approve, authorize, revoke, one card). The progress rail stays and must reflect each step live.
Corrects D28's "a question answered in the chat": there are no questions. The chat input remains for the person to interject, never as a required step.

Decision of 2026-10-23, later (wallet placement and signing)

D31

Wallet and Settings are separate; the wallet is a permanent block at the bottom of the sidebar.

Wallet and Settings are separate. The menu has Settings, Services, Conversations. The wallet lives at the bottom of the sidebar as a permanent block (address, network, total ≈ wp); it opens the wallet panel (balances, grouped authorizations with Revoke, export / import key, sign out). The top-bar address and Sign out go away.

D32

Every signature goes through the wallet's signing panel; one Sign signs the whole group in sequence.

No signature card inside a conversation or a page. Every wallet signature (sign in, new-conversation approve / authorize, the deployment's caps, the Contracts group, the Verify group, fund submitter, mint, revoke) is requested through the wallet: the wallet slides out from its sidebar block with a signing panel that lists the transactions of the request; one Sign signs the whole group in sequence (each line turns signed with its tx), Reject fails that step and the agent reports it. The page or conversation only shows "waiting for the wallet" until then.
The agent's run pauses only at those requests.

D33

No Title field in the New conversation dialog: the title is the first message; the dialog's one big figure is the total ≈ wp.

New conversation dialog: no Title field. A conversation is created without a title; its title is the first 80 characters of its first message (whitespace collapsed), as the Engine's defaultTitle and the old Woodpecker do; it can be renamed later from the conversation header. The dialog's summary is the total authorization in wp, shown as the one prominent figure of the dialog (the amount the person remembers), next to the Create button; per-token caps stay small and inline. Signing after Create goes through the wallet panel (D32), never a button in the dialog.
2026-10-23

Decisions of 2026-10-23 (kinds and pricing, from the discussion with Steven)

D34

A kind is a contract of interfaces (runner, memory, model, tool, host); a label is only a display name.

kind is a convention, not a label. A service that declares a kind promises the interfaces of that kind, and the Console relies on them without reading anything else. A service may declare several kinds. label is only the developer's display name in the descriptor.
Required interfaces per kind: model — an agent-chat route (OpenAI-style chat with tools, tool messages and streaming, metered by usage) plus /pricing; tool — one or more tool routes with a JSON-Schema parameter block and a pricing rule each, plus /pricing; runner — create / submit / watch / abort a conversation, derive identities, pay dependencies with the conversation identity; store — the durable conversation storage API (commit, read, scan); cloud — deploy a Worker, put a secret, bind a Durable Object, read logs, delete. A kind comes from the template or preset the service was deployed with; it is never typed by hand. Whether the directory contract records kinds is the open item above.

D51a, D52a · D3 and D34 kind lists → D51a and D52a: the kinds are runner, memory, model, tool, host.

D35

Pricing is one of fixed, tiered or metered, then numbers; the contract only ever sees (max, actual).

Pricing is a choice among fixed forms, then numbers. Each tool route (or the model route) carries one pricing rule: fixed (one price per call), tiered (a measure of the request — a number at a path, a string length, code points or body bytes — and [limit, price] tiers), or metered (a max rule for the quote and an actual rule from the response, or a shipped preset such as openai-usage, apify-usage, bytes-tiers), plus maxPerCall. The developer picks the form in the deploy form and sets the numbers; the preset proposes both. The contract only ever sees (max, actual); the Console shows the rule as fixed · 1 tR2 per call, tiered · ≤ 6 tVoice, metered · ≤ 100 tGpt, with the ≈ wp view.
Same three forms as the v1 gateway spec §3.1; period and conditional stay reserved. In the mock's deploy form the pricing block is implied by the preset; a later change may expose form + numbers as fields.

D36

Each kind and preset has a default pricing; the preset other is discussed with the agent and confirmed on a card.

Pricing comes with the kind and the preset; other is discussed with the agent. Every kind has a default pricing form (model: metered by usage; tool: fixed per call, or tiered when the preset defines a measure; runner: metered per turn; store: fixed per commit; cloud: metered per operation), and every known preset carries its numbers. The deploy form shows the resulting rule in one editable line. The Preset select gets an other entry for an API no preset knows: then, and only then, the agent asks in the chat (what the API is, its routes and parameters, a free check path, the pricing form and numbers), proposes a summary card, and continues only after the person confirms that card.
The one exception to D30 (no questions in the chat). The run after the confirmation is the same as for a preset.

D37

label is a free search tag, never part of the service name.

label is a user-defined tag for search. It is free text the developer chooses, shown as a small tag next to the display name and matched by the search box; it is not an identifier and never part of the name.
Several tags may come later; one text field for now.

Decisions of 2026-10-23 (the conversation view)

D38

The conversation view: a spends strip above the composer; the authorization is a button with meters and a popover with editable caps and Revoke.

The conversation view is redesigned around the composer. The transcript takes the width. Above the composer runs a spends strip: one scrolling line of chips, newest first, one chip per paid call (kind icon, name, actual amount, state), with a link to the full spends sheet. The authorization is a button in the composer bar: collapsed, it shows each token's remaining as a small graphic meter (ring or bar, remaining / cap) and the total remaining ≈ wp; opened, it is a popover above the composer with the identity (address, copy), the per-token rows (cap, used, reserved, remaining, ≈ wp), editable caps with a Submit changes action that asks the wallet for a new authorize (through the wallet panel, D32), and Revoke per token. No separate Identity / Authorization / Spends cards on the right.
The functions stay as they are; only the layout and the interaction change. The look follows a written design plan (tokens, type scale, layout concept) made with the design skill.

D39

Every service has a simple monochrome icon by kind; a developer may pick one at deploy.

Every service has an icon. Default by kind (runner, store, model, tool, cloud); a developer may pick one at deploy from a small set of simple monochrome vector icons (lucide line icons); no emoji, no colored or pictorial icons (amended 2026-10-23). It shows wherever the service is named: Directory and My services rows, the New conversation dialog, the conversation header, the spends chips, the management page.

D40

The wallet opens in two steps: a compact popover, then the full dialog with the tabs Balances and Authorizations.

The wallet opens in two steps. The sidebar block's expand control opens a compact popover first (anchored above the block, about the block's width ×1.3): address with copy, network, ETH, total ≈ wp, the count of active authorizations, the top token balances, and two actions: Open wallet and Sign out. Open wallet opens the full wallet dialog, which has two tabs: Balances and Authorizations (the footer keeps Export key, Import key, Sign out).
2026-10-23, Steven's review of Change 10.

D41

A model is not a tool: a chat gateway is offered only as the conversation's model.

A model is not a tool. A chat gateway has kind model and is offered only as the conversation's model. Its chat route is not listed among the tools. (Calling one model from another is not a use case of v2.)
2026-10-23, Steven's review of the dialog; in the Change 15 draft.

Decisions of 2026-10-23, later (provider, starter tokens, wording, effort)

D42

Own services live only in My services, with Manage; the Directory lists other owners' services, with Add.

Own services live only in My services. A service this wallet deployed never appears in the Directory; it is in My services from deployment on, with Manage. The Directory lists other owners' services; Add copies one into My services.

D43

The provider woodpecker@0a1b publishes the runner, the llm, the memory and the host service (cf); a new wallet starts with them.

The provider woodpecker@0a1b publishes a runner (Worker + DO bundled in one service, no store dependency, metered per turn), an llm model and a cf cloud service. A new wallet starts with the runner and the llm in My services; it adds the cloud service before its first deployment.
Solves the chicken-and-egg of the first deployment without a bundled-deployment flow.

D43 "no store dependency" still holds: the runner commits to the memory service the wallet chose, paid by the conversation's agent, not as a runner dependency.

D44

Starter tokens for a new wallet: 50 tRunner, 50 tLLM, 50 tMemory and 20 tCloud.

Starter tokens: the provider gives a new wallet 50 tRunner, 50 tLLM and 20 tCloud (and the wpCredit balance), enough to try conversations and deploy a first service.
Shown in the wallet as "Starter pack from woodpecker@0a1b".

D45

Signing requests speak plainly: the purpose and the wp amount first; the conversation identity is called the agent.

Signing requests speak plainly. The panel leads with the purpose and the wp amount; the transactions sit under a collapsed Details; the conversation identity is called the agent (e.g. "the agent of ‹title›"); the authorization contract is "Woodpecker's authorization contract"; one network-fee line.
Change 17.

D46

Effort is a conversation setting (off … max): a default in Settings, changed from the conversation header, no signature.

Effort (thinking level) is a conversation setting: off, minimal, low, medium, high, xhigh, max; chosen in the New conversation dialog next to the model, changeable from the conversation header, with a default in Settings. No signature: it is a runner parameter, not a payment.
Change 18.

D53 · D46 "chosen in the New conversation dialog" → D53 (the dialog has a Memory select instead; effort starts from the Settings default and changes from the conversation header).

Decisions of 2026-10-23, evening (sign-in, the map's scope and form)

D47

The runner's Worker only forwards by wallet address; the DO verifies the sign-in itself: challenge, signature, session credential.

The runner's Worker only forwards; the DO verifies the sign-in itself. The Worker reads the claimed wallet name chainId:address (lower-case) from the request, checks only its format, takes the Durable Object by that name (getByName) and forwards the request. The DO issues the challenge (domain, nonce, expiry; the nonce kept in memory), verifies that the signature recovers to its own address (ctx.id.name), stores a session credential with an expiry in its own storage and checks it on every request; sign-out deletes it. No global secret in the Worker, no database, no registry of DOs; a junk request writes nothing.
Replaces the D1 note "the Worker issues a short-lived credential". Payment is not a sign-in concern: any wallet may sign in; the runner checks the agent's tRunner remaining on contract A before every turn. Alternative recorded, not chosen: the embedded wallet key signs every request (no challenge, no session); it would prompt on every request once external wallets are supported.

D48

Current scope is direct tokens only: proxy tokens, nested billing, the Intent fund field and the bundled deployment are deferred.

Current scope: direct tokens only. Proxy tokens, the store service, nested billing, the Intent fund field and the bundled deployment (D6–D9, D20–D24, D27) are deferred. They stay in this log; the architecture map and the first v2 documents do not show them. The runner bundles its Worker and DO in one direct service (D43); the directory's uses field is deferred with them.
Steven, 2026-10-23.

D51, D51a · D48 "the store service is deferred" → D51 and D51a (the memory service, a direct service, is in scope); proxy tokens, nested billing, the Intent fund field and the bundled deployment stay deferred.

D49

The architecture map shows numbered steps with a narration panel; response arrows are allowed; the runner is one frame around its DO.

The architecture map shows numbered steps. Each flow is an ordered list of steps. The step number sits on the edge; the info panel lists the steps as sentences when a flow is selected. A response arrow is allowed when it carries a step (thin, open arrowhead; legend entry "response"). The Worker router is not a box: the runner is one frame woodpecker@0a1b/runner that contains the DO, with a note that the Worker is the entry and forwards by wallet address.
Change 21.

D49a

A flow step that happens inside one party (for example "import the key" in the Console) has no edge; its number badge sits in the top-right corner of that party's box, and the box lights up. Everything else of D49 stands.
Change 35, WoodpeckerMock5.

Decisions of 2026-10-23, late (where state lives; the store returns; the hosting kind)

D50

Where state lives: the chain (balances, authorizations, directory, own services), the memory service (conversations, settings record), the runner's DO (identity root, sessions, running turns), the browser (key, language, theme, last-used runner and memory).

Where each piece of state lives. The wallet is a key and holds nothing. On chain: token balances; authorizations (cap, used, reserved per wallet, agent, token); the service directory; which services are the wallet's own (directory owner). In the wallet's store (D51): the conversations (transcript, title, status, spends) and the wallet's settings record (My services and their default caps; default model, effort, runner and store). In the runner's DO: the identity root, the sessions, the running turns and a cache of the conversations it works on. In the browser only: the wallet key (exported and imported by the person), language, theme, and the last-used runner and store, with the provider's as the defaults (D43).
Steven, 2026-10-23: "补上吧,没这个不行". The Conversations list and My services are read from the store; the Directory and the balances from the chain; a new browser finds the settings record in the default store and the preferred runner in it.

D51

The memory service: a direct service (woodpecker@0a1b/memory, tMemory, fixed 1 per commit) that keeps the conversations and the settings record; the runner commits each completed turn; the owner signs in to it as to the runner.

The store service returns, as a direct service. Kind store (D34): durable conversation storage with commit, read and scan, plus the wallet's settings record. Default woodpecker@0a1b/store, token tStore, fixed 1 tStore per commit (D36), in My services from the start with the runner and the llm (D43), 50 tStore in the starter pack (D44). The runner commits each completed turn to the conversation's store with an Intent signed by the conversation's agent (token = tStore); the store's submitter reserves and settles on contract A. The owner wallet signs in to the store as to the runner (D47) and reads its conversations and writes its settings record free of charge; the agent that committed a conversation may read it. The store is chosen per wallet in Settings and per conversation in the New conversation dialog, next to the runner. Any wallet may deploy its own store from the store preset (a Worker + Durable Object storage, no upstream key).
Revises D48 for the store only: proxy tokens, nested billing, the Intent fund field and the bundled deployment stay deferred. Consequence: the runner is replaceable; the conversations stay in the store when the runner changes.

D51a

The service of D51 is called memory: kind memory, default woodpecker@0a1b/memory, token tMemory, fixed 1 tMemory per commit. Nothing else is renamed: the "settings record" keeps its name, conversations keep theirs.
Steven, 2026-10-23: "memory 吧 就 store 改 memory 不要乱改其他的名字".

D52

The kind cloud is renamed host; woodpecker@0a1b/cf keeps its name and its token tCloud.

The kind cloud is renamed hosting. A hosting service deploys and runs the Workers of gateways, runners and stores: deploy a Worker, put a secret, bind a Durable Object, read logs, delete (the D34 interfaces, unchanged). The service woodpecker@0a1b/cf keeps its name and its token tCloud; only its kind changes. Kinds are now runner, store, model, tool, hosting.
Proposed word hosting (alternatives: host, deployer); Steven to confirm the word.

D52a

The kind of D52 is host (not hosting). woodpecker@0a1b/cf and tCloud unchanged. Kinds: runner, memory, model, tool, host.
Steven, 2026-10-23.

Amendments of 2026-10-23, late (names fixed by Steven)

D53

The New conversation dialog has a Memory select in place of Effort; effort comes from the Settings default and is changed from the conversation header.

New conversation dialog: the Effort select is removed; in its place a Memory section with the select of the conversation's memory service (default woodpecker@0a1b/memory, chosen like the runner) and its cap row (tMemory). Effort is no longer chosen in the dialog: a conversation starts with the default effort from Settings and can be changed from the conversation header (D46 amended). The Settings page keeps Default runner, Default model, Default effort and Theme, and gets a Default memory select.
Steven, 2026-10-23: "是 new conversation 页面" (corrects the first reading, which put the change on the Settings page).