Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
120 commits
Select commit Hold shift + click to select a range
b150a22
fix(server): a keyless daemon starts a new chat on its configured pri…
Broccolito Sep 11, 2026
7b77f9d
test(privacy): point AR-15's closure scan at update_agent_provider
Broccolito Sep 11, 2026
51d863c
fix(desktop): say when a chat fails to start, and keep what was typed
Broccolito Sep 11, 2026
a80ca71
fix(desktop): every start-failure notice offers Copy error
Broccolito Sep 11, 2026
fe97758
docs(serve): SD-9 — a new chat starts on the operator's model without…
Broccolito Sep 11, 2026
ddaa856
fix(server): the keyless-daemon warning says what SD-9 still allows
Broccolito Sep 11, 2026
3b13365
style(desktop): prettier on the surface test
Broccolito Sep 11, 2026
7ea48e7
style(server): rustfmt the SD-9 tests
Broccolito Sep 11, 2026
0dcc509
fix(privacy): one reach gate for every HTTP route that names a chat o…
Broccolito Sep 11, 2026
e3896e5
docs(desktop): say what the capability header changes for a browser tab
Broccolito Sep 11, 2026
936f7f8
fix(desktop): send the user's proof on every call the reach gate now …
Broccolito Sep 11, 2026
5a9f3fb
test(privacy): run the knowledge-base sweep and the serve standing wh…
Broccolito Sep 11, 2026
ccc3e79
test(privacy): the knowledge-base sweep covers the credibility overri…
Broccolito Sep 11, 2026
01115e7
test(privacy): reach the serve standing through the library path the …
Broccolito Sep 11, 2026
3f9ae47
sessionBindingSync: announce the app-wide model selection across windows
Broccolito Sep 11, 2026
750d3d7
desktop: every window states the model its next new chat will run on …
Broccolito Sep 11, 2026
11270a5
docs: model selection across windows (F3), and P4's decoupling in the…
Broccolito Sep 11, 2026
6579877
feat(agent): enforce the checklist for multi-step turns (planning gate)
Broccolito Sep 11, 2026
5ca5978
fix(planning-gate): checked string access for clippy::string_slice; t…
Broccolito Sep 11, 2026
6b6f508
desktop: "Also use for new chats" ticks when its square is clicked
Broccolito Sep 11, 2026
21abab8
docs: model selection across windows — measured runtime results
Broccolito Sep 11, 2026
9dd9319
feat(planning-gate): log whether a turn is gated
Broccolito Sep 11, 2026
aec4078
docs(todo): the intro claims no more than the stop check enforces
Broccolito Sep 11, 2026
b52f0fe
Merge #240 (SD-11) into current main for the CLI follow-up that stand…
Broccolito Sep 11, 2026
48d3463
Merge remote-tracking branch 'origin/main' into claude/sad-brattain-1…
Broccolito Sep 11, 2026
85af195
Merge origin/main into fix/f3-app-model-cross-window
Broccolito Sep 11, 2026
2d0a072
Merge origin/main into fix/serve-private-default-new-chat
Broccolito Sep 11, 2026
88c26d5
test(desktop): stub the privacy-off note in the Hub start-failure test
Broccolito Sep 11, 2026
970e730
fix(desktop): a workflow captured from a chat with no primary has no …
Broccolito Sep 11, 2026
7c76088
fix(desktop): only the Default control names a workflow's primary kno…
Broccolito Sep 11, 2026
4eabd13
feat(active-work): read one registry entry by id
Broccolito Sep 11, 2026
57510c9
fix(developer): a shell command's active-work row names the chat that…
Broccolito Sep 11, 2026
d42ed37
Merge origin/main (6455bc21) into claude/sweet-pare-965d18
Broccolito Sep 11, 2026
6f2a5c5
Merge origin/main (d6b39693) into claude/sweet-pare-965d18
Broccolito Sep 11, 2026
01f4a28
fix(privacy): /active_work lists and stops only the work of chats the…
Broccolito Sep 11, 2026
edbff6a
chore(api): regenerate the OpenAPI spec and client for the /active_wo…
Broccolito Sep 11, 2026
4207c02
test(desktop): a call to the active-work routes must carry the person…
Broccolito Sep 11, 2026
0722c11
docs(privacy): /active_work is gated; record the no-chat decision and…
Broccolito Sep 11, 2026
46d5f7e
fix(cli): ask the daemon before asking for the user-action key (SD-11…
Broccolito Sep 11, 2026
7cd22cf
test(server): pin the refusal shapes the terminal reads for the user-…
Broccolito Sep 11, 2026
f6347f8
docs: the terminal asks the daemon before it asks for the user-action…
Broccolito Sep 11, 2026
d8cd7be
fix(web): biorouter web serves no transcripts, and gates the turn tha…
Broccolito Sep 11, 2026
ade905e
fix(cli): read a chunked empty refusal as empty, not as a body of "0"
Broccolito Sep 11, 2026
fbef097
refactor(cli): keep the key-verdict types to the module that reads them
Broccolito Sep 11, 2026
d5ad76c
Merge remote-tracking branch 'origin/main' into claude/nice-villani-4…
Broccolito Sep 11, 2026
0141dae
Merge remote-tracking branch 'origin/main' into claude/gifted-shtern-…
Broccolito Sep 12, 2026
6d12136
Merge remote-tracking branch 'origin/main' into claude/great-panini-6…
Broccolito Sep 12, 2026
0c02e1d
Merge remote-tracking branch 'origin/main' into claude/sad-brattain-1…
Broccolito Sep 12, 2026
92da12c
Merge remote-tracking branch 'origin/main' into fix/f3-app-model-cros…
Broccolito Sep 12, 2026
f276111
Merge remote-tracking branch 'origin/main' into fix/serve-private-def…
Broccolito Sep 12, 2026
1a690bf
Merge remote-tracking branch 'origin/main' into claude/sweet-pare-965d18
Broccolito Sep 12, 2026
187cd21
Merge remote-tracking branch 'origin/claude/sweet-pare-965d18' into c…
Broccolito Sep 12, 2026
9105063
fix(baam): the marketplace shelves answer a phrase, not a substring
Broccolito Sep 12, 2026
c4056bd
fix(privacy): stopping a scheduled run is gated wherever it is asked for
Broccolito Sep 12, 2026
4b0b39f
fix(ui): let Tab reach a dialog's actions, and say the dialog is modal
Broccolito Sep 12, 2026
15a315b
fix(workflows): a new chat that cannot take its knowledge bases is di…
Broccolito Sep 12, 2026
93aa328
fix(privacy): inspecting a schedule names its chat only to a caller t…
Broccolito Sep 12, 2026
e544ccd
fix(settings): give the four Appearance switches an accessible name
Broccolito Sep 12, 2026
a0f46a9
fix(ui): dismiss a tooltip when its target leaves the page
Broccolito Sep 12, 2026
da27d72
fix(chat): tell the user when copying a message fails
Broccolito Sep 12, 2026
4dbd056
fix(workflows): an explicitly empty knowledge selection is saved as e…
Broccolito Sep 12, 2026
c05d30b
fix(ui): make the checkbox square itself clickable
Broccolito Sep 12, 2026
640cfe6
fix(web): the chat page stops reflecting the URL into script context …
Broccolito Sep 12, 2026
1a0b4c1
fix(privacy): a schedule listing names only the chats the caller coul…
Broccolito Sep 12, 2026
7dcff3b
fix(permissions): a coding agent's framing is not a security finding
Broccolito Sep 12, 2026
ca9cd53
style(test): prettier the new bridge contract guard
Broccolito Sep 12, 2026
ce3b86a
fix(agent-drafter): esbuild discovery stops at the checkout it is run…
Broccolito Sep 12, 2026
3a69518
Merge remote-tracking branch 'origin/main' into fix/ui-a11y-and-appro…
Broccolito Sep 12, 2026
dd16583
Merge remote-tracking branch 'origin/main' into claude/great-panini-6…
Broccolito Sep 12, 2026
55ac5c7
Merge remote-tracking branch 'origin/main' into fix/f3-app-model-cros…
Broccolito Sep 12, 2026
1e25123
docs(privacy): the schedule residual is closed; regenerate the contract
Broccolito Sep 12, 2026
ac504b9
docs: a measured subagent count, seven runnable filters, and why BEDR…
Broccolito Sep 12, 2026
94db1d9
Merge remote-tracking branch 'origin/main' into claude/sad-brattain-1…
Broccolito Sep 12, 2026
037f82c
fix(serve): the browser token an operator set is the one that is used
Broccolito Sep 12, 2026
ec61536
fix(apps): `apps serve` stops the daemon it started, however it ends
Broccolito Sep 12, 2026
8984320
fix(cli): attach says what leaving actually does, not that it cancels
Broccolito Sep 12, 2026
a6f0d24
fix(web): the socket gets an origin check, and the tokens stop being …
Broccolito Sep 12, 2026
a621678
fix(schedule): a scheduled agent run made from a terminal needs a person
Broccolito Sep 12, 2026
b7f0ce6
fix(server): the steer gate hands back its refusal instead of a large…
Broccolito Sep 12, 2026
7bc3abe
Merge remote-tracking branch 'origin/main' into claude/ecstatic-einst…
Broccolito Sep 12, 2026
78a3437
Merge remote-tracking branch 'origin/main' into fix/serve-token-apps-…
Broccolito Sep 12, 2026
79c4490
Merge remote-tracking branch 'origin/main' into claude/gifted-shtern-…
Broccolito Sep 12, 2026
9e83583
Merge remote-tracking branch 'origin/main' into claude/nice-villani-4…
Broccolito Sep 12, 2026
9def9be
Merge remote-tracking branch 'origin/main' into claude/nostalgic-ferm…
Broccolito Sep 12, 2026
a2d94fa
fix(providers): error copy that does not contradict itself, and a /mo…
Broccolito Sep 12, 2026
68cf246
fix(server): SD-12's keyless exemption is pinned to the launch config…
Broccolito Sep 12, 2026
8958565
fix(desktop): the launcher declares the user-action key it sends
Broccolito Sep 12, 2026
030e04b
docs(privacy): BIOROUTER_MODEL decides which model runs, never which …
Broccolito Sep 12, 2026
94c1896
test(privacy): AR-15's guard pins raise_baseline's wiring, not just i…
Broccolito Sep 12, 2026
a24ac30
Merge remote-tracking branch 'origin/main' into fix/provider-copy-wor…
Broccolito Sep 12, 2026
4a9891a
Merge remote-tracking branch 'origin/main' into fix/ui-a11y-and-appro…
Broccolito Sep 12, 2026
ac03920
docs(approval-card): the prompt guard covers the bridge only, and say…
Broccolito Sep 12, 2026
b064f7a
Merge remote-tracking branch 'origin/main' into fix/f3-app-model-cros…
Broccolito Sep 12, 2026
e3bbec2
Merge remote-tracking branch 'origin/main' into claude/sad-brattain-1…
Broccolito Sep 12, 2026
9cb4e7a
merge main into the web-transcripts branch
Broccolito Sep 12, 2026
360a4e3
land #240: the steer gate hands back its refusal instead of a large Err
Broccolito Sep 12, 2026
a1702ca
land #229: a new chat starts on the host's configured private model
Broccolito Sep 12, 2026
4057cb9
land #247: every window's model chip follows the app-wide selection
Broccolito Sep 12, 2026
a9f9e35
land #250: enforce the checklist for multi-step turns (planning gate)
Broccolito Sep 12, 2026
7250d4e
land #268: six measured interaction and a11y defects
Broccolito Sep 12, 2026
dd8a444
land #261: the terminal asks the daemon before it asks you for the us…
Broccolito Sep 12, 2026
5674bf2
land #267: biorouter web serves no transcripts, gates the turn that r…
Broccolito Sep 12, 2026
c21a8b6
land #273: four serve / apps serve / CLI lifecycle defects
Broccolito Sep 12, 2026
f9d836a
Merge remote-tracking branch 'origin/main' into fix/provider-copy-wor…
Broccolito Sep 12, 2026
8d2f210
integration: three defects only the merged tree has
Broccolito Sep 12, 2026
3bdae1f
land #256: a workflow never invents a primary knowledge base
Broccolito Sep 12, 2026
9071a62
Merge origin/main into claude/ecstatic-einstein-dd05d6
Broccolito Sep 12, 2026
28dce89
fix(merge): re-aim three pointers the merge invalidated, and re-measu…
Broccolito Sep 12, 2026
35be9bb
Merge origin/main into claude/great-panini-672c85
Broccolito Sep 12, 2026
8a80fbc
fix(search): a licence republished as a tag is no longer searchable
Broccolito Sep 12, 2026
f9c2fd2
refactor: three functions back under clippy::too_many_lines
Broccolito Sep 12, 2026
d5d5a7b
fix(test): the source-read window uses `get`, not a slice that can panic
Broccolito Sep 12, 2026
903fc1a
land #257: /active_work shows and stops only the work of chats the ca…
Broccolito Sep 12, 2026
d6fa86c
land #276: the licence is also a TAG, and all three matchers still se…
Broccolito Sep 12, 2026
dc52342
land #277, and compose the two marketplace-search fixes into one rule
Broccolito Sep 12, 2026
2f674f6
fix(privacy): Gate H's ratcheting half, so a public chat cannot priva…
Broccolito Sep 12, 2026
f0d2961
land #278: Gate H's ratcheting half
Broccolito Sep 12, 2026
d9fd545
test(serve): the terminal's steer question answers to the SETTLED SD-…
Broccolito Sep 12, 2026
636e1f2
land #256: pick up its newer tip
Broccolito Sep 12, 2026
b1d3232
test(desktop): the tab strip spies on scrollIntoView instead of redef…
Broccolito Sep 12, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
69 changes: 66 additions & 3 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -293,6 +293,26 @@ what did not" section first**; the rest of that document is the design, not the
- **Knowledge bases ratchet too.** A base takes the tier of the most sensitive session that wrote to
it (four write choke points), is refused to a public caller at the read choke points, and a
refusal names what it refused. `biorouter-mcp/src/knowledge/tier*.rs`.
- **Holding the daemon secret does not make a caller the user.** That was the premise behind
leaving the `/knowledge/*` read routes, `GET /sessions` and `DELETE /sessions/{id}` ungated. A
public chat's shell recovers the secret with `ps eww`, and QA used it to read a private base and
delete a private chat (H2/M1/M2/F0, 2026-09-10). Every HTTP route that names a chat or a
knowledge base now asks `routes::session_reach`'s one decision: a private target needs the
user-action proof or a stated private capability. The rules that follow:
- A route that names one chat calls `session_reach`, and refuses with its exact plain text.
- Listings filter through `HttpCaller::lists_session`.
- Running work is the same rule reached through the row's chat. `GET /active_work` filters
through `HttpCaller::lists_work`, and its cancel asks `work_reach` before anything stops. A
row that names no chat is treated as a private chat's, so a registrant that knows its chat must
set `ActiveWorkItem::session_id`. The shell's rows take it from the `_meta` session id.
- Every `/knowledge/bases/{id}` route sits in `knowledge::router`'s `base_routes`, behind
`gate_knowledge_base`. Put any new `{id}` route there.
- ⚠ **The renderer must send `userActionHeaders()` on every such call.** A missing proof is not an
error: private rows silently vanish, and the Knowledge view's prune effects then read them as
deleted.
- A `biorouter serve` browser gets its operator's tier on listings and knowledge bases only
(SD-10).
- The wiring census (`crates/biorouter/tests/privacy_guard_wiring.rs`) counts every call site.
- **Affiliation is a third axis** (DR-26, plan Phase 6): tier asks *how sensitive*, affiliation asks
*whose*. HIPAA compliance does not transfer between institutions, so a UCSF model reaching another
institution's private connector is warned/refused even though both endpoints are Private.
Expand Down Expand Up @@ -1209,15 +1229,18 @@ Test the gate where it is: the unit tests in `agents/agent.rs`
(`subagents_enabled_injects_the_workspace_extension_with_the_spawn_tool_only`,
`an_explicit_workspace_entry_still_hides_the_spawn_tool_when_delegation_is_off`,
`subagents_disabled_injects_nothing`), via
`cargo test -p biorouter --lib -- subagent` (102 tests).
`cargo test -p biorouter --lib -- subagent` (**198 tests, measured 2026-09-12** — this
line said 102 for long enough that a "pre + N" assertion against it would have read a
shortfall of ninety-six as a pass; re-measure rather than trusting the figure, which
moved 197 → 198 between this line being written and the branch carrying it landing).

### Browser access (`biorouter serve`)

`biorouter serve` (alias `headless`) starts `biorouterd`, points it at the built interface and
prints a URL. The daemon serves the SPA **on its own origin**, so nothing is proxied. This
replaced a standalone `biorouter-headless` binary and its Linux tarball, both deleted
2026-08-23; release assets went 11 → 10. Design and reasoning:
[`docs/deployment/serve-decisions.md`](docs/deployment/serve-decisions.md) (SD-1..SD-9, SD-11),
[`docs/deployment/serve-decisions.md`](docs/deployment/serve-decisions.md) (the `SD-n` records),
[`serve-architecture.md`](docs/deployment/serve-architecture.md),
[`browser-access.md`](docs/deployment/browser-access.md).

Expand All @@ -1230,6 +1253,39 @@ replaced a standalone `biorouter-headless` binary and its Linux tarball, both de
**agent**, so every surface that writes a capability key asks `isBrowserSurface()`
(`ui/desktop/src/utils/surface.ts`) and explains *before* the user can reach the 409. Do not
"fix" browser mode by weakening the refusal.
- **A new chat starts on the configured model without a proof, and nothing else does** (SD-12).
Until it, a `serve` daemon with a private provider configured refused EVERY `/agent/start`
(the 2026-09-10 QA's F1): the new-chat bind asked for a proof a keyless daemon cannot check.
Four pieces, each load-bearing — measured by removing it: on a keyless daemon
`new_chat_bind_decision` (`routes/agent.rs`) lets the configured default bind, while a keyed
daemon still refuses a proof-less private first bind; `raise_baseline` makes a keyless
daemon's `/agent/update_provider` measure every move onto a private model from Public, or the
exemption would carry sideways to a private model nobody configured; the browser states the
host's model as `X-Caller-Provider` (`userActionHeaders()` on `isBrowserSurface()`), without
which a chat's first reply ratcheted it private and its next request 403'd; and
`biorouter_server::launch` **pins the exemption to the configuration the daemon was launched
with**. Tests:
`cargo test -p biorouter-server --test new_chat_no_user_key` (its own binary: the digest is a
process-global `OnceLock`).
⚠ **The exemption's first justification was FALSE and the fix is that pin.** It rested on
*"`/agent/start` binds `BIOROUTER_PROVIDER`, a key only a proven person may write"*. The HTTP
doors are shut, but `config.yaml` is not an HTTP resource: DR-14's filesystem deny is DEFERRED,
the agent holds `developer__shell`, and `Config`'s cache is keyed on a `FileStamp` it re-`stat`s
per read — so a model with a shell on a keyless daemon configured PUBLIC could write a private
provider into the file and get a 200 with Private capability where `main` answers 409 (measured
2026-09-12). The pinned set is `privacy::CAPABILITY_CONFIG_KEYS` verbatim plus `BIOROUTER_MODEL`;
pinning the provider NAME alone is not enough, because flipping `OLLAMA_HOST` to loopback moves
`ollama`'s tier with the name untouched. ⚠ And `NoKeyInstalled` is **not** the same thing as
"this is `serve`" — a desktop spawn satisfies it when `userActionKey` is undefined or the
daemon's bounded 2s stdin read times out. That case is a repairable fault, so the desktop
launcher declares its intent in `BIOROUTER_USER_ACTION_EXPECTED` and such a daemon keeps
`main`'s refusal plus a startup `ERROR`. ⚠ `BIOROUTER_MODEL` is in neither capability-key list
by decision, not oversight: no `tier()` implementation reads the model name (all five checked),
so it is an integrity key and its row lives in `NOT_CAPABILITY_CONFIG_KEYS`. ⚠ **Still unreachable in a browser, and out of SD-12's scope:**
`/agent/cancel` and `/interrupt` require the proof unconditionally, so Stop and mid-turn
steering cannot work on a keyless daemon. ⚠ `privacy_ar15_is_retired.rs`'s closure scan took
the FIRST `TierRaiseNeedsUser` in `routes/agent.rs`, which from `eb594ded` was the new-chat gate
and not AR-15's — it now starts at `update_agent_provider`.
- **A control that can never work here says so, before it is touched** (SD-8). The same
`Stdio::null()` that closes SD-1 means NO approval carrying `requires_user_proof` can ever
be granted on a `serve` daemon — for anyone, always. So `confirm_tool_action` answers a
Expand All @@ -1250,11 +1306,18 @@ replaced a standalone `biorouter-headless` binary and its Linux tarball, both de
reaches the same effect through `/agent/stop` and `/reply`, and `/reply` is refused `409` by
the BR-33 single-turn lock in the exact state where a steer lands — so admitting it would add
silent mid-turn injection into a turn already in flight, which nothing else there can do
(`reply.rs::authorize_steer`). Its keyless refusal carries `STEER_NO_KEY` and is **never an
(`reply.rs::steer_refusal`). Its keyless refusal carries `STEER_NO_KEY` and is **never an
empty 403**, because an empty turn-control 403 is how `biorouter session attach` recognises a
daemon that holds a key and asks the person for it. A subagent's tab stays refused throughout.
⚠ Keyless behaviour can only be tested in its own binary (the digest is a process-global
`OnceLock`): `cargo test -p biorouter-server --test turn_control_no_user_key`.
⚠ **The CLI reads the refusal's shape, not its status.** `biorouter session cancel` / `attach`
/ `send` cannot ask a daemon whether it holds a key, so they send without the proof and ask the
person for the key only on turn control's **empty** 403 — the keyed `Unproven` arm; every
keyless refusal carries a sentence and is printed instead (`key_verdict` in
`commands/session_watch.rs`). A sentence added to `Unproven`, or an empty keyless refusal,
breaks the terminal silently — one never prompts on the desktop's daemon, the other prompts a
`serve` user for a key that does not exist. Pinned from both sides.
- **Proof of a person is checked at the resolution choke point, not at one route.** Every door
that answers a parked decision — the HTTP route, an Agent Drafter app's WebSocket, ACP, the
CLI prompt, the TUI modal, an ancestor agent's relay — passes a `DecisionAuthority` into
Expand Down
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 3 additions & 0 deletions crates/biorouter-cli/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,9 @@ serial_test = { workspace = true }
# The workspace's process-wide environment lock, so env-mutating tests here
# exclude every other one rather than only the `#[serial]` ones.
env-lock = { workspace = true }
# A WebSocket client, so `commands::web`'s tests can drive the page's socket the
# way the page does. The version axum's `ws` feature already locks.
tokio-tungstenite = "0.28.0"
# Issue #56 DR-20 / Task 55. `biorouter session declassify <id>` raises the OS
# authentication prompt, so its TESTS would type a real password on every run
# without a stand-in.
Expand Down
36 changes: 31 additions & 5 deletions crates/biorouter-cli/src/cli.rs
Original file line number Diff line number Diff line change
Expand Up @@ -532,6 +532,24 @@ fn parse_key_val(s: &str) -> Result<(String, String), String> {
}
}

/// ⚠ **An empty token is not a token, and `--auth-token ""` used to be accepted
/// as one.** Passing it made `validate_network_auth` see `Some(_)` and let
/// `--host 0.0.0.0` through, while `commands::web`'s middleware would then admit
/// anyone who sent `Authorization: Bearer ` with nothing after it — so the one
/// check whose entire job is to insist on protection was satisfied by its
/// absence. Refused here, at parse time, so the mistake cannot reach a bind; a
/// whitespace-only value is refused for the same reason.
pub(crate) fn parse_auth_token(s: &str) -> Result<String, String> {
if s.trim().is_empty() {
return Err(
"an empty --auth-token is not a token; omit the flag to run without one (loopback \
binds only), or pass a real secret"
.to_string(),
);
}
Ok(s.to_string())
}

#[derive(Subcommand)]
enum SessionCommand {
#[command(about = "List all available sessions")]
Expand Down Expand Up @@ -668,7 +686,7 @@ enum SessionCommand {
no_wait: bool,
#[arg(
long,
help = "Read the daemon's raw user-action key from the first line of stdin instead of prompting on the controlling terminal"
help = "For a daemon started with a user-action key: read the raw key from the first line of stdin, instead of being asked for it on the terminal once the daemon wants it"
)]
user_action_key_stdin: bool,
},
Expand Down Expand Up @@ -699,7 +717,7 @@ enum SessionCommand {
read_only: bool,
#[arg(
long,
help = "Read the daemon's raw user-action key from the first line of stdin instead of prompting on the controlling terminal"
help = "For a daemon started with a user-action key: read the raw key from the first line of stdin, instead of being asked for it on the terminal once the daemon wants it"
)]
user_action_key_stdin: bool,
},
Expand All @@ -709,7 +727,7 @@ enum SessionCommand {
session_id: String,
#[arg(
long,
help = "Read the daemon's raw user-action key from the first line of stdin instead of prompting on the controlling terminal"
help = "For a daemon started with a user-action key: read the raw key from the first line of stdin, instead of being asked for it on the terminal once the daemon wants it"
)]
user_action_key_stdin: bool,
},
Expand Down Expand Up @@ -1616,7 +1634,11 @@ enum Command {
port: u16,

/// Use this access token instead of a freshly generated one
#[arg(long, help = "Use this access token instead of generating one")]
#[arg(
long,
help = "Use this access token instead of generating one. Takes precedence over \
BIOROUTER_BROWSER_TOKEN, which is read when this is not given."
)]
token: Option<String>,

/// Serve without an access token
Expand Down Expand Up @@ -1672,7 +1694,11 @@ enum Command {
open: bool,

/// Authentication token for both Basic Auth (password) and Bearer token
#[arg(long, help = "Authentication token to secure the web interface")]
#[arg(
long,
value_parser = parse_auth_token,
help = "Authentication token to secure the web interface"
)]
auth_token: Option<String>,

/// Allow running without authentication when exposed on the network (unsafe)
Expand Down
Loading
Loading