Skip to content

Commit d4c94e5

Browse files
authored
feat!: remove the --user/KB_USER surface from local commands (#165)
The local surfaces (task CLI, TUI, MCP) no longer select a board owner: --user and the KB_USER environment fallback are gone, and every dispatch seam passes the literal "default" to the store. The store API keeps its user parameter and the schema is unchanged, so kb serve's wire contract and storage keys are untouched. Databases that still hold tasks under another namespace keep them; local commands print one warning line naming those namespaces and leave the data alone. kb mcp parses its flags with ContinueOnError so an unknown flag is a usage error instead of a process exit, matching kb serve. Closes #164
1 parent 552f69a commit d4c94e5

20 files changed

Lines changed: 287 additions & 198 deletions

.claude/skills/kb-issues/SKILL.md

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -14,10 +14,8 @@ chosen, where a workflow reaches for `gh issue` or `glab issue`, use the
1414

1515
## Environment
1616

17-
- `KB_USER` — board owner every command operates on (default `default`).
18-
An explicit `--user` flag beats it. Identities are lowercased; stick to
19-
`[a-z0-9._@-]`.
20-
- `KB_DATA` — data directory override.
17+
- `KB_DATA` — data directory override. Local commands always operate on the
18+
single `default` board; there is no per-user selection.
2119
- `KB_SERVER` + `KB_SERVER_TOKEN` — operate against a running kb server
2220
over HTTP instead of the local database.
2321
- MCP-capable agents can run `kb mcp` and use the board tools directly
@@ -43,7 +41,7 @@ chosen, where a workflow reaches for `gh issue` or `glab issue`, use the
4341
| `gh issue comment N --body B` | `kb comment add <id> "B"` |
4442
| view comments | `kb comment list <id> [--json]` |
4543
| delete a comment | `kb comment rm <cid> --yes` (ids are `c1, c2, ...`, stable) |
46-
| assignees | one board per user: `--user name`; `kb users` lists boards |
44+
| assignees | not modelled: local kb is one board. `kb users` lists any legacy owners still in the database |
4745

4846
Run `kb help` for every flag (priority, due dates, effort, checklists,
4947
blocked flag, status moves).

README.md

Lines changed: 18 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -49,15 +49,15 @@ kb
4949
When both stdin and stdout are TTYs, a bare `kb` opens the full-screen TUI.
5050
When either stream is redirected, it prints root help and exits successfully
5151
without creating or opening the data directory. `kb tui` remains the explicit
52-
form and accepts `--data` and `--user`.
52+
form and accepts `--data`.
5353

5454
```sh
55-
kb tui --data ~/.local/share/kb --user default
55+
kb tui --data ~/.local/share/kb
5656
kb --help
5757
```
5858

59-
The default data directory is `$KB_DATA` or `~/.local/share/kb`. The default
60-
board owner is `$KB_USER` or `default`.
59+
The default data directory is `$KB_DATA` or `~/.local/share/kb`. Local modes
60+
always operate on the `default` board.
6161

6262
## Terminal UI
6363

@@ -67,7 +67,7 @@ The TUI is the primary human interface. It includes:
6767
- card detail, markdown rendering, comments, and blocker links;
6868
- create/edit forms with labels, due dates, effort, priority, checklists, and
6969
blocked state;
70-
- persistent text and label filters per board owner;
70+
- persistent text and label filters per board;
7171
- keyboard lift/drop and mouse drag moves with filtered-order correctness;
7272
- completion guards, tick-all/force-ship choices, auto-ship, unship, cancel,
7373
restore, and permanent deletion;
@@ -105,11 +105,14 @@ The data directory contains:
105105
- `kb.db`, the SQLite database;
106106
- `secret`, the generated encryption secret when `KB_SECRET` is unset;
107107
- `skills/`, optional user skill overrides;
108-
- TUI preference state scoped by database and board owner.
108+
- TUI preference state scoped by database path.
109109

110-
Board owners are normalized to lowercase and may contain ASCII letters,
111-
digits, `.`, `_`, `@`, and `-`. Use `--user NAME` or `KB_USER` consistently
112-
across the TUI, CLI, and MCP server.
110+
The TUI, task CLI, and MCP server all operate on the single `default` board.
111+
Board owners still exist in the schema, because `kb serve` serves one board per
112+
authenticated identity, but they are not selectable from local commands. A
113+
database written by an older version that holds tasks under another owner keeps
114+
them; local commands print one warning line naming those namespaces and leave
115+
the data alone. `kb users` lists them, and `kb serve` still serves them.
113116

114117
Provider API keys and forge tokens are encrypted at rest with AES-256-GCM.
115118
Keep the `secret` file with the database. Losing it makes stored credentials
@@ -140,9 +143,9 @@ Root server flags are rejected with exit code 2 and point to `kb serve`, so an
140143
old service fails visibly instead of silently launching the wrong mode.
141144

142145
If an old Entra-backed deployment used the immutable `oid` claim as its board
143-
owner, pass that value with `--user` or `KB_USER`. Token-mode deployments use
144-
the former `X-KB-User` value. Browser-only session tokens and display state are
145-
not database records and are not migrated.
146+
owner, that board is still served by `kb serve` under the same identity.
147+
Browser-only session tokens and display state are not database records and are
148+
not migrated.
146149

147150
Update service units and container commands before replacing the binary. A
148151
reverse proxy may continue forwarding `/api/*` for API clients, but there is no
@@ -173,13 +176,12 @@ unique UUID prefix also work. `cancel` is reversible. `rm --yes` permanently
173176
deletes a Cancelled task. Moving to Done is refused while checklist items or
174177
blockers remain unless `--force` is explicit.
175178

176-
Every task command accepts `--data`, `--user`, and `--json`. Set `KB_SERVER` to
177-
use the same verbs against an optional HTTP server:
179+
Every task command accepts `--data` and `--json`. Set `KB_SERVER` to use the
180+
same verbs against an optional HTTP server:
178181

179182
```sh
180183
export KB_SERVER=http://127.0.0.1:8080
181184
export KB_SERVER_TOKEN=shared-secret
182-
export KB_USER=alice
183185
kb list
184186
```
185187

@@ -191,7 +193,7 @@ kb list
191193
HTTP server is required.
192194

193195
```sh
194-
kb mcp --data ~/.local/share/kb --user default
196+
kb mcp --data ~/.local/share/kb
195197
```
196198

197199
Example configuration:
@@ -331,7 +333,6 @@ returned in settings responses.
331333
| Variable | Used by | Meaning |
332334
| --- | --- | --- |
333335
| `KB_DATA` | all local modes, serve | Data directory |
334-
| `KB_USER` | TUI, CLI, MCP | Default board owner |
335336
| `KB_SECRET` | all store users | Encryption secret override |
336337
| `KB_SERVER` | task CLI | Optional remote API base URL |
337338
| `KB_SERVER_TOKEN` | task CLI | Bearer token for remote mode |

dispatch.go

Lines changed: 16 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -183,15 +183,26 @@ func versionString(info *debug.BuildInfo, ok bool) string {
183183
return out
184184
}
185185

186-
// runMCP serves the board over MCP stdio: kb mcp [--data DIR] [--user NAME].
186+
// defaultBoardUser is the single board namespace every local surface (CLI,
187+
// TUI, MCP) operates on. The --user/KB_USER selection was removed; the store
188+
// and the HTTP wire API keep their user parameter for kb serve.
189+
const defaultBoardUser = "default"
190+
191+
// runMCP serves the board over MCP stdio: kb mcp [--data DIR].
187192
func runMCP(args []string) error {
188-
fs := flag.NewFlagSet("kb mcp", flag.ExitOnError)
193+
return runMCPWithFlagOutput(args, os.Stderr)
194+
}
195+
196+
// runMCPWithFlagOutput keeps flag failures returnable (kb serve does the same)
197+
// so an unknown flag is a testable usage error instead of a process exit.
198+
func runMCPWithFlagOutput(args []string, output io.Writer) error {
199+
fs := flag.NewFlagSet("kb mcp", flag.ContinueOnError)
200+
fs.SetOutput(output)
189201
dataDir := fs.String("data", defaultDataDir(), "board storage directory (env KB_DATA)")
190-
user := fs.String("user", envOr("KB_USER", "default"), "board user the tools operate on (env KB_USER)")
191202
if err := fs.Parse(args); err != nil {
192-
return err
203+
return &webFlagError{err: err}
193204
}
194-
return mcpRun(*dataDir, *user)
205+
return mcpRun(*dataDir, defaultBoardUser)
195206
}
196207

197208
// defaultDataDir resolves the board storage directory: KB_DATA if set, else

dispatch_test.go

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -83,11 +83,19 @@ func TestRunMCPPassesResolvedFlags(t *testing.T) {
8383
return nil
8484
}
8585
wantData := filepath.Join(t.TempDir(), "boards")
86-
if err := runMCP([]string{"--data", wantData, "--user", "Alice.Work"}); err != nil {
86+
if err := runMCP([]string{"--data", wantData}); err != nil {
8787
t.Fatalf("runMCP: %v", err)
8888
}
89-
if gotData != wantData || gotUser != "Alice.Work" {
90-
t.Fatalf("mcp args = %q, %q; want %q, Alice.Work", gotData, gotUser, wantData)
89+
if gotData != wantData || gotUser != defaultBoardUser {
90+
t.Fatalf("mcp args = %q, %q; want %q, %s", gotData, gotUser, wantData, defaultBoardUser)
91+
}
92+
93+
// The board namespace is no longer selectable from the command line.
94+
var flagOutput bytes.Buffer
95+
err := runMCPWithFlagOutput([]string{"--user", "alice"}, &flagOutput)
96+
var flagErr *webFlagError
97+
if !errors.As(err, &flagErr) || !strings.Contains(err.Error(), "flag provided but not defined: -user") {
98+
t.Fatalf("--user should be rejected: %v", err)
9199
}
92100

93101
mcpRun = func(string, string) error { return errors.New("serve failed") }

0 commit comments

Comments
 (0)