Repository navigation
Description
Summary
The elicitation broker is where mcpx puts the most sensitive data it handles — questions routed to a human precisely because an agent should not hold them (password/credential-shaped fields, per elicit.Route), sampling prompts "stored exactly as sent", and the answers — and it is the least protected store in the daemon. On current main the broker DB sits in a 0755 directory any local user can read, no row is ever deleted, and the full question and answer are broadcast as event-bus data to every subscriber. The one human surface over the store, mcpx elicit, prints raw URLs with no domain emphasis or punycode warning, pre-fills "..." instead of schema defaults, and answers with no review step. This design gives the broker an owner-only home with migration for existing installs, a documented retention bound, summary-only event payloads, and a review-first answering surface.
Design doc: files/designs/code-mcpx-elicitation-broker-hygiene.md in the keep-the-four-repos-healthy goal workspace (full audit, alternatives, risks, open questions).
No Drew direction decision needed: origin dezren39/darwin-nix#255's acceptance is explicit (owner-only store verified on disk; pruning with a documented bound), the owner-only precedent is already in-tree (internal/artifacts and the state dir at 0o700), and the judgment calls (dedicated 0700 subdir rather than tightening the shared logs dir; summary-only events; retention defaults of 30 days / 1000 terminal rows) are recorded in the design doc.
Current state (verified on main d39e611, 2026-10-28)
- Both broker open sites create the shared
<state>/logsdir withdefaults.PublicDirMode(0755,internal/defaults/defaults.json:214):internal/daemon/hooks.goOpenBroker(~L288-294) andinternal/cli/elicit.gobroker()(~L37-44).elicit.Open(internal/elicit/elicit.go~L155) createselicit.db(+ WAL/SHM) with default modes. Gapselicitation-state-storage-protectedandelicitation-server-follow-best-practices(internal/conformance/coverage_clientfeatures.go, origin mcpx: elicitation storage is readable by any local user and never pruned; elicitation UI and response validation rows dezren39/darwin-nix#255). internal/elicit/elicit.gocontains noDELETE:expireOverdue(~L437) only transitions pending → expired. Every question, answer, and sampling request accumulates forever. Gapsampling-messages-not-retained-between-requests.- Full payloads on the bus:
events.ElicitOpenedwithData: mustJSON(req)andevents.ElicitAnsweredwithData: mustJSON(ans)atinternal/daemon/hooks.go~L164-171,internal/daemon/consumer.go~L325/424/505,internal/daemon/routes_proto.go~L669,internal/daemon/server.go~L1395. No in-tree consumer reads answer content from the bus — askers useBroker.Await. Gapssampling-both-handle-sensitive-data(client + server). renderQuestion(internal/cli/elicit.go~L201-232) already shows the asking server/tool; what is missing is exactly the fix(id): coalesce LogSync ingest batches (#241) #255 UI slice: URL domain emphasis + punycode warning, schema defaults pre-filled (todayexampleFor~L275-285 emits"..."), and a review step before an answer is relayed. Six gaps:elicitation-app-review-modify-responses,elicitation-client-form-review-modify-responses,elicitation-client-url-show-domain-and-consent,elicitation-client-handle-urls-carefully,elicitation-client-highlight-domain,elicitation-client-warn-punycode.- Explicitly NOT this design: validating answers against
requestedSchema— the client slice is mcpx: Phase 3 of #1481 — validate elicitation form answers against requestedSchema in client.answer #1484 (Phase 3 of design design(mcpx): JSON Schema validation of tool input and output — one validator at the client choke point #1481, queued); the server-relay slice (elicitation-server-validate-received-data) stays open on nix#255 until mcpx: Phase 3 of #1481 — validate elicitation form answers against requestedSchema in client.answer #1484's as-built shape is known. Also distinct: the tasks store's own0755dir creation (internal/tasks/tasks.go:149) belongs to design(mcpx): tasks, finished — one task store for MCP and /v1, and a client that can call task-required tools #1554's store, not this one.
Proposal (phased; each phase independently landable)
- Phase 1 — owner-only store. One path helper in
internal/elicit; the store moves to a dedicated state subdir at0700, DB files0600; a legacylogs/elicit.dbis migrated on open with pending questions preserved; modes are tightened on open for pre-existing installs and failure to tighten is an error. Both open sites use the helper. - Phase 2 — bounded retention + redacted events (gated on Phase 1). Terminal rows pruned on open by age + count bounds from
defaults.json(30 days / 1000 rows, recorded defaults); pending rows never pruned.ElicitOpened/ElicitAnsweredpayloads become summary-only (id, server, tool, mode, audience, state, expiry — never message/schema/url/content) at all publish sites, with a tree-wide consumer audit. - Phase 3 — review-first answering surface + truth-up (gated on Phases 1–2). URL domain emphasis + punycode warning; schema defaults pre-filled in form rendering; interactive render-and-confirm for
mcpx elicit answerwith a script-preserving opt-out (non-interactive behaviour unchanged). Retire the six elicit-ui gaps; completion evidence on mcpx: elicitation storage is readable by any local user and never pruned; elicitation UI and response validation rows dezren39/darwin-nix#255 — commenting, not closing (its validation acceptance is only partly this design's).
Open questions (stay questions; not filed)
- Should the logs directory itself go owner-only later (log index can carry tool-call arguments)? Its own design if evidence appears.
- Should sampling rows get a different retention bound than form answers? One bound until size evidence argues otherwise.
- Does the OpenCode plugin (out-of-tree) read bus payload fields Phase 2 removes? To confirm in Phase 2 triage; the fix is routing it through the broker read path, not restoring the leak.
- Full TUI edit-in-place for answers vs render-and-confirm? Evidence from actual use first.
Acceptance (design level)
- Phases 1–3 filed as sub-issues of this issue and landed.
- Fresh and upgraded installs:
elicit.db+ its directory owner-only, verified on disk; a question pending across the upgrade is still answerable. - Terminal history bounded by the documented age/count limits; pending never pruned.
- No bus event carries a question's message/schema/URL or an answer's content.
mcpx elicitshows the asking server, the URL domain called out (punycode warning where applicable), defaults pre-filled, and an interactive review before relay.- mcpx: elicitation storage is readable by any local user and never pruned; elicitation UI and response validation rows dezren39/darwin-nix#255 carries the completion evidence with its remaining validation slice named honestly.
agent-note:v1 — filed by repo design architect (dedicated code job, pass 8, 2026-10-28)
- task: design origination for the nix#255 elicitation/sampling hygiene cluster, audited against main d39e611
- outcome: design doc written (
files/designs/code-mcpx-elicitation-broker-hygiene.mdin the keep-the-four-repos-healthy goal workspace); 3 phases to be filed as sub-issues and enqueued as triage packets - dedupe: searched code issues 2026-10-28 (
elicit storage,elicit.db,punycode,broker store,prune elicitation) — no existing issue covers this scope; mcpx: Phase 3 of #1481 — validate elicitation form answers against requestedSchema in client.answer #1484 owns only the requestedSchema-validation slice
Activity
dezren39 commentedon Oct 28, 2026
agent-note:v1 — filed (design originated, queue task n/a — architect run 2026-10-28)
dezren39 commentedon Oct 28, 2026
agent-note:v1 — CORRECTION to the filed note on this issue (2026-10-28)
dezren39 commentedon Oct 29, 2026
Program tending — Phase 1 child closed
Program-tender note (2026-10-29): sub-issue #1676 (Phase 1 of this design) closed 2026-10-29T00:37Z. The remaining phases #1677 and #1678 are still open and were active today (updated 2026-10-29T13:43Z / 13:30Z), so the next step is simply those phases proceeding — nothing is blocked on this epic itself.
23 remaining items
dezren39 commentedon Nov 3, 2026
🤖 Agent note · handed off
dezren39 commentedon Nov 3, 2026
🤖 Agent note · picked up
dezren39 commentedon Nov 3, 2026
🤖 Agent note · triage verdict — complete; closing parent
repo-worker-code, OpenChamber scheduled lane (ec118cad-0fd3-4652-91c4-27432f2f2efd)developing-today/codemain52fd50d17e750ae84385b5b41414e886eccee95eand fresh GitHub state, 2026-11-03.All three phases of this design are complete: #1676/#1677/#1678 are CLOSED and their implementation PRs are MERGED — #1724 (
2953f274), #2202 (7c52ced1), #3011 (16d6d5a8). Current main contains the owner-only store tests (pkgs/mcpx/internal/elicit/store_test.goasserts0700), prune-on-open atinternal/elicit/elicit.go:213-232, and retention defaults720h/1000. The review-first CLI phase and its test evidence are in merged #3011. The required completion evidence was posted on relocated tracker #1954, and the legacydezren39/nix#255cross-reference names the remaining server-relay validation slice.Scope boundary: requested-schema/server-relay validation was explicitly excluded from this three-phase design. A separate validation PR #2646 is currently OPEN; it does not block #1675 acceptance. No live PR remains for any #1675 phase.
Verdict: the design issue’s acceptance is met; no further split or queue task is needed. Closing #1675 as completed.