Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
90 commits
Select commit Hold shift + click to select a range
238da56
refactor(config,session): rename periodic -> loop core types/tags/set…
inercia Jul 1, 2026
70f949b
feat(migration): rename periodic.json->loop.json + settings periodic_…
inercia Jul 1, 2026
a97c5cd
refactor(config,processors): rename periodic -> loop template vars/CE…
inercia Jul 1, 2026
aceb921
refactor(conversation): rename periodic->loop in conversation domain …
inercia Jul 1, 2026
d83d798
refactor(mcpserver): rename periodic->loop MCP tool params/types/desc…
inercia Jul 1, 2026
37287aa
refactor(web,acpproc): rename periodic->loop loop-runner engine + acp…
inercia Jul 1, 2026
46267c4
refactor(web): rename periodic->loop REST/WS contracts + routes (mitt…
inercia Jul 1, 2026
93a1592
mitto-8ir.7: loop rename: frontend API/data layer (endpoints, hooks, …
inercia Jul 1, 2026
4da01de
mitto-8ir.7: rename lib.js periodic exports to loop
inercia Jul 1, 2026
95fb5a2
mitto-8ir.7: rename useWebSocket periodicStarted state export to loop…
inercia Jul 1, 2026
b9b233a
mitto-8ir.7: app.js — fix broken /periodic REST paths + follow lib/ho…
inercia Jul 1, 2026
524a0f7
mitto-8ir.9: rename builtin prompt periodic->loop (frontmatter loop:,…
inercia Jul 1, 2026
afd73de
mitto-8ir.8 inc1: rename Periodic* component files/symbols, Periodic*…
inercia Jul 1, 2026
a705b8d
mitto-8ir.8 inc2: rename shared periodic->loop hook/component identif…
inercia Jul 2, 2026
41fdca5
mitto-8ir.8 inc3: rename all remaining periodic->loop in web/static (…
inercia Jul 2, 2026
f200269
mitto-8ir.8: preserve historical 'periodic' literal in migrateLegacyT…
inercia Jul 2, 2026
789b695
fix(mitto-8ir): repair 7 builtin processor enabledWhen gates broken b…
inercia Jul 2, 2026
7931f6c
mitto-8ir.10: rename periodic->loop in docs, README, CLAUDE.md, AGENT…
inercia Jul 2, 2026
2413df9
mitto-8ir.11: rename periodic->loop in test client + backend stragglers
inercia Jul 2, 2026
c412d3e
mitto-8ir.11: reword 'periodically' prose in builtin prompts/processors
inercia Jul 2, 2026
edf8445
mitto-8ir.11: rename periodic->loop in Playwright E2E specs
inercia Jul 2, 2026
6a33f74
mitto-8ir.11: rename periodic->loop in Go integration tests
inercia Jul 2, 2026
055af6a
feat(conversation): per-child initial model profile for auto-children
inercia Jul 2, 2026
6eb4cb0
fix(web): preserve workspace selection on Workspaces dialog reopen
inercia Jul 2, 2026
f5700d8
fix(conversation): deliver queued human free-text verbatim on templat…
inercia Jul 2, 2026
810c620
chore(config): apply gofmt formatting
inercia Jul 2, 2026
345df62
chore(prompts): rename builtin iterate prompts to loop
inercia Jul 2, 2026
240d5c8
feat(prompts): fall back to the jira CLI when JIRA MCP tools are unav…
inercia Jul 2, 2026
839c691
fix(web): flush pending workspace edits when switching selection in W…
inercia Jul 2, 2026
0360e90
feat(web): rich workspace and model-profile dropdowns for auto-create…
inercia Jul 2, 2026
53dd087
style(web): reformat styles.css with prettier
inercia Jul 2, 2026
0025020
fix(web): soften global focus indicator with an accent glow
inercia Jul 2, 2026
210851d
feat(web): extract shared Toolbar and promote conversation actions to…
inercia Jul 2, 2026
fd018f2
test(ui): update Playwright specs for toolbar refactor
inercia Jul 2, 2026
dfb7864
refactor(prompts): rename beads discuss to assess and add new discuss…
inercia Jul 2, 2026
4c57693
docs(rules): refresh component-extraction and testing agent rules
inercia Jul 2, 2026
539c8b7
feat(session): runtime-configurable agent inactivity watchdog timeout…
inercia Jul 2, 2026
ba06935
fix(beads): align detail-panel toolbar and fix mobile layout
inercia Jul 2, 2026
3b6a068
feat(prompts): add onTasks loop trigger with CEL condition gating
inercia Jul 2, 2026
4da03c8
feat(workspace): select auxiliary model by capability tag
inercia Jul 2, 2026
109cd8f
feat(ui): per-folder prompt shortcut buttons in conversation and issu…
inercia Jul 2, 2026
21fe914
feat(prompts): add beads-refine-implementation loop builtin (mitto-mx4)
inercia Jul 2, 2026
5ef1225
feat(beads): configure prompt arguments for Pull/Push/Sync upstream a…
inercia Jul 3, 2026
1460cbf
docs(rules): expand debugging log-pattern guidance
inercia Jul 3, 2026
2ee09e3
fix(web): relax Split-IP CSRF fingerprint for mobile network drift (m…
inercia Jul 3, 2026
3dd57ff
fix(prompts): gate mitto_conversation_* prompts on deterministic Perm…
inercia Jul 3, 2026
e493d09
feat(config): add global shortcut buttons with backend API and defaults
inercia Jul 3, 2026
e6d9936
feat(ui): add ShortcutsEditor for global and folder shortcut buttons
inercia Jul 3, 2026
4981a2f
test(ui): add Playwright spec for adding workspace shortcuts
inercia Jul 3, 2026
d6d3443
docs: document global shortcuts feature and refresh agent rules
inercia Jul 3, 2026
79ac798
fix(ui): align ShortcutsEditor select rows in settings dialog
inercia Jul 3, 2026
2b457b2
docs(mcp): ADR for deterministic MCP tool discovery (mitto-1ae.2)
inercia Jul 3, 2026
e771c96
feat(prompts): add parallel child fan-out to loop & beads iteration p…
inercia Jul 3, 2026
e29a6ee
docs(mcp): expand tool-discovery ADR for dynamic/late-starting server…
inercia Jul 3, 2026
eb0d19e
fix(ui): snap tooltips to whole pixels to fix blurry text
inercia Jul 3, 2026
bf3689c
fix(ui): use dedicated loop/unloop icons for loop toggle buttons
inercia Jul 3, 2026
b30ccf1
refactor(ui): show prompt text in shortcut button tooltips
inercia Jul 3, 2026
0a94d75
feat(beads): add label add/remove and workspace label listing
inercia Jul 3, 2026
968f0db
feat(ui): pulse in-progress issue status badge in beads list
inercia Jul 3, 2026
62a3cab
feat(prompts): add Support Slack triage workflow prompts
inercia Jul 3, 2026
c201f59
feat(prompts): list "Loop until ..." in the prompts menu
inercia Jul 3, 2026
b72f577
feat(config): per-server MCP availability state model (mitto-sys.1)
inercia Jul 3, 2026
27932ea
feat(mcpdiscovery): direct stdio MCP tools/list discovery component (…
inercia Jul 3, 2026
fcad5b3
feat(beads): toggleable + button reveals inline add-label input
inercia Jul 3, 2026
e895040
feat(mcpdiscovery): wire stdio discovery to agents.Manager.ListMCPSer…
inercia Jul 3, 2026
236ec0f
feat(auxiliary): last-known-good MCP tools cache policy (two-consecut…
inercia Jul 3, 2026
4a1453d
feat(auxiliary): consume deterministic stdio MCP discovery in FetchMC…
inercia Jul 3, 2026
32e77da
feat(mcpdiscovery): http/sse tools/list discovery via Streamable/SSE …
inercia Jul 3, 2026
90bbf6c
feat(auxiliary): harden LLM MCP tool fallback - strict object schema …
inercia Jul 3, 2026
3f833cd
feat(mcpdiscovery): bounded exponential-backoff re-probe scheduler fo…
inercia Jul 3, 2026
c6f5a42
feat(mcpdiscovery): wire bounded-backoff re-probe of unreachable MCP …
inercia Jul 3, 2026
ae6a788
feat(mcpdiscovery): add ToolListWatcher primitive for event-driven to…
inercia Jul 3, 2026
6845f9f
feat(auxiliary): per-workspace MCP ToolListWatcher pool for event-dri…
inercia Jul 3, 2026
4f58b1e
feat(web): wire event-driven MCP ToolListWatcher pool into runtime + …
inercia Jul 3, 2026
d72f47a
refactor(web): remove blind 30/60/120s prompts_changed re-broadcast (…
inercia Jul 3, 2026
49dcd42
fix(agents): correct mcp-list.sh config paths for github-copilot and …
inercia Jul 4, 2026
0ec6eec
fix(agents): rewrite mcp-list.sh for opencode (correct path, mcp key,…
inercia Jul 4, 2026
eebd911
feat(agents): implement real mcp-list.sh for junie (mcpServers from ~…
inercia Jul 4, 2026
8937bc6
feat(agents): add Headers field to MCPServer and emit headers from mc…
inercia Jul 4, 2026
c10d9fb
feat(mcpdiscovery): apply MCPServer.Headers to network transports + h…
inercia Jul 4, 2026
b4eed7b
mitto-sys.8: persist real-MCP tools cache to disk (TTL + manual refresh)
inercia Jul 4, 2026
1f77aac
config: prune stale legacy .md builtins in EnsureBuiltinPrompts (mitt…
inercia Jul 4, 2026
f0f0124
feat(web): session statistics in conversation properties panel
inercia Jul 4, 2026
8e6c58d
fix(web): restore loop configuration on unarchive (mitto-vmp)
inercia Jul 4, 2026
3504cd8
fix(web): drop daisyUI tooltip on SessionPanel tabs to remove stray p…
inercia Jul 4, 2026
c4b956e
docs: document MCP tool discovery two-tier design and mcp-list.sh audit
inercia Jul 4, 2026
90cde86
fix(web): log beads read errors and retry transient failures (mitto-rxd)
inercia Jul 5, 2026
7e217fa
fix(config): quiet missing .beads dir in beads watcher (mitto-3zr)
inercia Jul 5, 2026
43d7004
test(integration): add missing Label/ListAllLabels stubs to onTasks b…
inercia Jul 5, 2026
472409b
fix(css): remove !important from beadsInProgressPulse keyframe (style…
inercia Jul 5, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
2 changes: 2 additions & 0 deletions .augment/rules/00-overview.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ Mitto is a CLI client for the Agent Client Protocol (ACP). It enables terminal-b
| [websockets/](../docs/devel/websockets/) | **WebSocket protocol** (message types, seq numbers, sync, reconnection, delivery verification) |
| [workspaces.md](../docs/devel/workspaces.md) | Multi-workspace, persistence |
| [follow-up-suggestions.md](../docs/devel/follow-up-suggestions.md) | Action buttons, auxiliary analysis, persistence |
| [mcp-tool-discovery.md](../docs/devel/mcp-tool-discovery.md) | Deterministic MCP tool discovery (stdio/http/sse) vs LLM-introspection fallback |

## Package Structure

Expand All @@ -35,6 +36,7 @@ internal/client/ → Go client for Mitto REST API + WebSocket (used in test
internal/config/ → Configuration loading (YAML/JSON)
internal/conversion/ → Markdown-to-HTML conversion, file link detection
internal/defense/ → Scanner defense, blocklist, IP metrics (used by web middleware)
internal/mcpdiscovery/→ Deterministic MCP tool discovery: connects to configured servers (stdio/http/sse) via modelcontextprotocol/go-sdk client; no internal/config or internal/web imports
internal/mcpserver/ → MCP servers (global debug + per-session)
internal/processors/ → Command processors (pre/post processing via external commands)
internal/runner/ → Restricted runner, sandbox execution (go-restricted-runner)
Expand Down
2 changes: 1 addition & 1 deletion .augment/rules/01-go-conventions.md
Original file line number Diff line number Diff line change
Expand Up @@ -137,4 +137,4 @@ if strings.Contains(err.Error(), "session not started") {
## JSON Marshaling

- **Nil vs empty slices**: `json.Marshal` encodes nil as `null`, empty as `[]`. ACP rejects `null` where array is required. Always initialize: `MCPServers: []MCPServer{}`. Mark with `// Must be empty array, not nil — ACP validates this`.
- **`omitempty` on bool**: Never use `omitempty` on `bool` fields where `false` is meaningful — Go omits `false` as zero value. Example: `PeriodicEnabled bool` must NOT have `omitempty`.
- **`omitempty` on bool**: Never use `omitempty` on `bool` fields where `false` is meaningful — Go omits `false` as zero value. Example: `LoopEnabled bool` must NOT have `omitempty`.
8 changes: 4 additions & 4 deletions .augment/rules/02-session.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ keywords:
| `Lock` | Session locking, heartbeat, cleanup | Yes (mutex + goroutine) |
| `Queue` | Message queue for busy agent | Yes (mutex) |
| `ActionButtonsStore` | Follow-up suggestions persistence | Yes (mutex) |
| `PeriodicStore` | Periodic prompt config per session | Yes (mutex) |
| `LoopStore` | Loop prompt config per session | Yes (mutex) |
| `Flags` | Available feature flags registry | N/A (read-only) |

## Immediate Persistence (Web Interface)
Expand Down Expand Up @@ -117,9 +117,9 @@ lock.SetWaitingPermission("File write") // During permission request

**Important**: Queue configuration is **global/workspace-scoped**, NOT per-session. See [docs/devel/message-queue.md](../docs/devel/message-queue.md) for config options, REST API, WebSocket notifications, and title auto-generation.

## Periodic Prompts (PeriodicStore)
## Loop Prompts (LoopStore)

Stored in `periodic.json`. Only top-level sessions may have periodic prompts (child → 400).
Stored in `loop.json`. Only top-level sessions may have loop prompts (child → 400).

**Key fields**:
- `PromptName` — references workspace prompt by name (resolved at send time via cache)
Expand All @@ -128,7 +128,7 @@ Stored in `periodic.json`. Only top-level sessions may have periodic prompts (ch
- `DelaySeconds` — wait after agent idle before firing (onCompletion only)
- `MaxDurationSeconds` — wall-clock cap since first run

**Critical**: Changing `PeriodicStore.Update()` signature requires updating BOTH `session_periodic_api.go` (PATCH handler) AND `mcpserver/server.go` (MCP tool) — both call `Update()`.
**Critical**: Changing `LoopStore.Update()` signature requires updating BOTH `session_loop_api.go` (PATCH handler) AND `mcpserver/server.go` (MCP tool) — both call `Update()`.

## Auxiliary Package

Expand Down
8 changes: 8 additions & 0 deletions .augment/rules/04-component-extraction.md
Original file line number Diff line number Diff line change
Expand Up @@ -94,3 +94,11 @@ Place in implementation file to catch interface breaking changes:
// Verify component satisfies interface at compile time
var _ conversation.SharedProcess = (*sharedSessionAnalyzer)(nil)
```

## Post-Extraction Cleanup

After extracting a component, **remove unused delegators** from original file:
- **Scan before merge**: Run `golangci-lint run ./internal/conversation` to find unused methods
- **Remove both**: Delegator method + corresponding test if only that method used the test
- **Keep pattern**: Only delegators actively called by other packages or public API
- **Example**: If `ConfigManager.GetConfig()` is extracted and `BackgroundSession.GetConfig()` delegator is never called externally, remove both (unless it's part of exported `SessionManager` interface)
4 changes: 2 additions & 2 deletions .augment/rules/05-msghooks.md
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ when: # required block — BOTH on: and match: are required
everyNTurns: 3 # fire every N responses; everyNTokens: 15000; afterInterval: 5m (all AND-logic)
priority: 100 # lower = earlier
enabled: true # false = never loads (build-time gate)
enabledWhen: 'acp.matchesServerType("augment") && !session.isPeriodic' # CEL runtime gate
enabledWhen: 'acp.matchesServerType("augment") && !session.isLoop' # CEL runtime gate
onError: skip # skip | fail

# Text-mode only (forbidden for agentResponded/agentIdle):
Expand Down Expand Up @@ -130,7 +130,7 @@ Key CEL variables/functions (full reference in `docs/config/processors.md`):
| Context | Examples |
| ----------------------- | --------------------------------------------------------------------------- |
| `acp.*` | `acp.matchesServerType("augment")`, `acp.name`, `acp.type`, `acp.tags` |
| `session.*` | `session.isPeriodic`, `session.isChild`, `session.id` |
| `session.*` | `session.isLoop`, `session.isChild`, `session.id` |
| `Session.ModelTags` | `Session.HasModelTag("smart")`, `"smart" in Session.ModelTags` — current model's tags from `models:` profiles (template: `{{ if Model "smart" }}`); empty when model unknown |
| `workspace.*` | `workspace.hasUserDataSchema`, `workspace.hasMittoRC`, `workspace.hasMetadataDescription`, `workspace.folder` |
| `children.*` | `children.exists`, `children.count`, `children.mcp_count`, `children.promptingCount`, `children.idleCount` |
Expand Down
12 changes: 6 additions & 6 deletions .augment/rules/07-prompts.md
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,7 @@ a plain conversation with no pre-selected issue.
4. Gate **every** `bd` command and id-specific `git grep` behind
`{{ if $target }} … {{ end }}` — mode 3 must emit **zero** `bd` calls.

**Exemplars**: `beads-issue-investigate`, `beads-issue-discuss`,
**Exemplars**: `beads-issue-investigate`, `beads-issue-assess`,
`beads-issue-status`, `beads-issue-resolved`, `beads-issue-work`.

**Guard tests**: `*ThreeModeTargetResolution` tests + `TestBuiltinPrompts_NoDeprecatedMittoVars`
Expand All @@ -127,13 +127,13 @@ Full recipe: [docs/config/prompts.md § Context-adaptive prompts (three modes)](

## Key Types

`WebPrompt`: Name, Prompt, Description, Group, BackgroundColor, Icon, Source ("builtin"|"file"|"settings"|"workspace"), Enabled (*bool: nil=enabled, false=disabled), EnabledWhen (CEL, server-side only), Periodic (non-nil = periodic conversation), Singleton (bool: `true` = no concurrent conversation instances for this prompt in the same working dir; see below).
`WebPrompt`: Name, Prompt, Description, Group, BackgroundColor, Icon, Source ("builtin"|"file"|"settings"|"workspace"), Enabled (*bool: nil=enabled, false=disabled), EnabledWhen (CEL, server-side only), Loop (non-nil = loop conversation), Singleton (bool: `true` = no concurrent conversation instances for this prompt in the same working dir; see below).

### Singleton Prompts (find-or-route)

A prompt with `singleton: true` must not have more than one non-archived conversation per working dir. A session records the prompt that created it in `session.Metadata.OriginPromptName` at create time (set on `POST /api/sessions` from `initial_prompt_name`/`origin_prompt_name`). When a singleton prompt is launched, `HandleCreateSession` (`internal/web/handlers/session_create.go`) scans existing non-archived sessions by `(WorkingDir, OriginPromptName)` under a keyed lock (`lockSingleton`); on a match it reuses that conversation instead of creating a new one — re-seeding the queue if idle, focus-only if busy — and responds with `reused: true`. The frontend threads `reused` through `useWebSocket.js` → `useConversationSeeding.js` and shows a "Reusing existing ..." toast instead of "Started ..." (`useBeadsIntegration.js`, `app.js`). Applied to the builtin beadsList maintenance prompts (overview, reevaluate, cleanup-stale, group-epics, status-all-inprogress) — deliberately **not** to "Start working on ready", since concurrent work-starting conversations are legitimate.

`PromptPeriodic` (YAML `periodic:`): `value`/`unit`/`at` (schedule period), `maxIterations`, plus the on-completion fields `trigger` (`schedule` default | `onCompletion`), `delay` (int seconds for onCompletion; clamped to the global floor), and `maxDuration` (duration string e.g. `4h`; wall-clock cap from the first run). `MaxIterations` caps scheduled runs; effective cap = min(prompt maxIterations, config default 100, hardcoded 1000). Backend auto-disables (not archives) when either the iteration cap or `maxDuration` is hit.
`PromptLoop` (YAML `loop:`): `value`/`unit`/`at` (schedule period), `maxIterations`, plus the on-completion fields `trigger` (`schedule` default | `onCompletion`), `delay` (int seconds for onCompletion; clamped to the global floor), and `maxDuration` (duration string e.g. `4h`; wall-clock cap from the first run). `MaxIterations` caps scheduled runs; effective cap = min(prompt maxIterations, config default 100, hardcoded 1000). Backend auto-disables (not archives) when either the iteration cap or `maxDuration` is hit.

## Merging & Caching

Expand All @@ -145,7 +145,7 @@ A prompt with `singleton: true` must not have more than one non-archived convers

## Menu-Driven Prompt Sends (Named-Prompt Mechanism)

All menus (prompts, beadsIssues, beadsList) send `prompt_name` only — never the full body. Frontend helpers in `useConversationSeeding.js`: `seedConversationWithPrompt()` (existing session), `startConversationWithPrompt()` (new ± periodic), `makePeriodicNow()` (convert to periodic). Backend resolves name at dispatch via `resolvePromptByName()` in target workspace context; the body is then **Go-template rendered** (if it contains `{{`) before `${VAR}` substitution. **Anti-pattern**: never POST resolved text to `/api/sessions/{id}/queue` — send `prompt_name` instead.
All menus (prompts, beadsIssues, beadsList) send `prompt_name` only — never the full body. Frontend helpers in `useConversationSeeding.js`: `seedConversationWithPrompt()` (existing session), `startConversationWithPrompt()` (new ± loop), `makeLoopNow()` (convert to loop). Backend resolves name at dispatch via `resolvePromptByName()` in target workspace context; the body is then **Go-template rendered** (if it contains `{{`) before `${VAR}` substitution. **Anti-pattern**: never POST resolved text to `/api/sessions/{id}/queue` — send `prompt_name` instead.

## MCP Prompt Tools

Expand Down Expand Up @@ -217,11 +217,11 @@ parameters:

## Iteration.IsUninterrupted (mitto-5xjn)

`{{ .Iteration.IsUninterrupted }}` is `true` only on a **scheduled** (non-forced, non-FreshContext) periodic run that directly follows another such run with nothing in between — no user interjection, no forced "run now", no FreshContext, same process lifetime.
`{{ .Iteration.IsUninterrupted }}` is `true` only on a **scheduled** (non-forced, non-FreshContext) loop run that directly follows another such run with nothing in between — no user interjection, no forced "run now", no FreshContext, same process lifetime.

**Reset boundaries** (set marker to false):
- Archive/unarchive, GC suspend/resume, process restart
- ACP process reinit/restart
- Periodic loop config change / pause / re-enable
- Loop loop config change / pause / re-enable

**Authoring rule**: compact "continue" branch must carry durable re-anchor (one-line goal + file/bead ref). Always render verbose form when `IsFirst || !IsUninterrupted` to reset context after interruptions.
14 changes: 14 additions & 0 deletions .augment/rules/08-config.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@ keywords:
- folder deduplication
- LoadFolders
- SaveFolders
- ShortcutButton
- global shortcuts
---

# Configuration System
Expand Down Expand Up @@ -117,6 +119,18 @@ Prompt `preferredModels` field (see `07-prompts.md`) references these profiles b

Agent metadata can pre-seed these at discovery: `metadata.yaml` `defaults.constraints` (plus `defaults.env`/`tags`/`autoApprove`) map onto `ACPServer.Constraints`/`Env`/`Tags`/`AutoApprove` via `seedACPServerDefaults` (see [03-cli-acp.md](03-cli-acp.md#agent-defaults-seeded-at-discovery)). Seeding is request-wins (user-supplied values are not overwritten).

## Global Shortcuts

Global shortcut buttons (`shortcuts:` in `settings.json`) mirror per-folder shortcuts (`folders.json`) and are merged with them **at render time** on the frontend — the backend stores and serves each level independently:

- Type: `config.ShortcutButton{Icon, Prompt}` (`internal/config/folders.go`) — `Prompt` is a workspace prompt name, `Icon` an optional `PROMPT_ICONS` key.
- Sections (map key in both global and folder JSON): `conversations`, `beadsIssue`, `tasksList`.
- API: `GET/PUT /api/global/shortcuts` (`internal/web/handlers/global_shortcuts.go`) mirrors the folder shortcuts endpoint; GET also returns the available `Prompts` so the editor needs only one request.
- `buildNewSettings` must preserve `shortcuts:` so an unrelated Settings save never wipes global shortcuts.
- Defaults for new installs are seeded in embedded `config/config.default.yaml` (`shortcuts:` key) — written to `settings.json` on first run only; existing installs are untouched.

Frontend merge/dedupe logic (duplicated in `BeadsView.js` ×2 and `app.js`): global list first, then folder entries whose `prompt` isn't already in the global list. See `25-web-frontend-components.md` for the shared `ShortcutsEditor` UI component.

## WorkspaceSettings Override Pattern

`WorkspaceSettings.ACPCommandOverride`: set default from server map, then apply override. See `internal/config/merger.go` for `GenericMerger[T]`.
2 changes: 1 addition & 1 deletion .augment/rules/11-web-backend-sequences.md
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ When a tool call or thought arrives from ACP, force-flush the MarkdownBuffer:
| Method | Behavior | When to Use |
| ------------- | ------------------------------------ | ------------------------------------- |
| `Flush()` | Force flush, ignores markdown state | Tool calls, thoughts, prompt complete |
| `SafeFlush()` | Only flush if not in table/list/code | Periodic/timeout flushes |
| `SafeFlush()` | Only flush if not in table/list/code | Loop/timeout flushes |

## Observer Patterns

Expand Down
Loading
Loading