Make the plan-usage statusLine exporter delegate instead of replacing the user's statusline #405
Replies: 3 comments
|
Thanks for the writeup. The diagnosis is correct, and I confirmed every part of it against master (1.28.0). The exporter is written into The bare word is real too, and there are three paths to it, not one. Seven repositories is not bad luck either. One thing that makes it worse than you described, and that I want fixed in the same pass: nothing takes the exporter back out. On your four questions:
There is a fifth question your list does not cover, and it is the one that decides the shape for me: Docker cases. The current command is portable by construction, env vars plus curl, and None of that is a no. The problem is real, the pattern you picked is the right one to copy, and delegating is the right instinct. Rebase first, the branch is 25 commits behind, and open the PR once the Docker path and the precedence question have answers. Posting the design here first was the right call under CONTRIBUTING even if the branch came before the thread. |
|
Opened #416 with your branch as the first commit, credited to you as-is, plus one follow-up commit that answers the questions above so the thread does not have to wait on a second round. What the follow-up changes:
Your tests run the shim as a real subprocess; the follow-up adds the injected command run the same way, with the shim path pointed at nothing to cover the container's view. Gate and CI are green. If you want to look over the follow-up commit, the PR is the place; otherwise it goes out in the next release pass. |
|
Change of plan on the mechanism, same outcome for you, and a better one. #361 from @timkjr had been reworked in parallel to stop Codeman writing a statusLine into One limit worth knowing: sessions running inside a Docker case no longer feed the Plan Usage chip, since the flag rides local spawns only. The chip is account-wide, so any local Claude session covers it, and threading the flag into the container launch is a follow-up. Ships in the next release. Thanks for the diagnosis, it is what settled the design. |
Uh oh!
There was an error while loading. Please reload this page.
The problem
Codeman injects a
statusLineinto each managed repo's.claude/settings.local.jsonso the Plan Usage chip gets liverate_limitsnumbers. Claude Code ranks that project file above~/.claude/settings.json, so the injection replaces whatever statusline the user configured globally.The replacement is not silent, and it is worse than just losing your own line. The exporter prints whatever
/api/status-telemetryreturns. That route answerscodemanfor a session id it does not know, so runningclaudeby hand in a managed repo makes the statusline the single wordcodeman. I hit this across seven repositories before working out where it came from.applyStatusLineConfigalready refuses to overwrite a hand-authoredstatusLine, and that guard works. It does not catch this case, because the user's line is inherited from~/.claude/settings.jsonrather than written into the repo, so there is nothing in the file for the guard to see.What I would like to propose
Keep the data tap and give the line back. The exporter becomes a generated shim that forwards the same blob to
/api/status-telemetry, resolves the statusline its own entry shadows, runs that command with the same blob on stdin, and prints its output. Codeman's footer still appears when there is nothing to shadow, so the exporter keeps its value for a user with no statusline of their own.The shim follows
deepseek-status-shim.tsclosely, since that pattern is already in the repo and solves the same distribution problem. It is a versioned.mjswritten into the data dir throughdataPath(), refreshed when its marker changes, and written with temp-and-rename because a live render can be executing the path during a refresh.Three details are worth calling out:
statusLinethat is not Codeman's own. Resolving late means a user who edits their global statusline sees the change with no reinjection.isCodemanStatusLine()still accepts the old/api/status-telemetrycommand. Without that second form, every repo an older Codeman managed would read as hand-authored, the upgrade would refuse to touch it, and the user would keep the replacing exporter forever.What I have and where
I built this before opening a Discussion, which is the wrong order under CONTRIBUTING, and I am posting rather than sending a PR so the design gets a look first. The branch is here if it is useful:
https://github.com/irisitymichaelgrundberg/Codeman/tree/feat/statusline-shim-delegates
It adds
src/statusline-shim.ts, rewiresgenerateStatusLineCommand()and the ownership check inhooks-config.ts, and updates the plan-usage sections ofCLAUDE.mdanddocs/architecture-invariants.md. There are 25 tests acrosstest/statusline-shim.test.tsandtest/hooks-config.test.ts. The shim tests run the real generated file as a subprocess against a live listener, becausetscnever sees it.npm testis green at 6828, and typecheck, lint, format and the frontend syntax check all pass. I have been running it on my own machine since this morning.Questions I would want answered before a PR
statusLinein the repo's ownsettings.local.json? My branch keeps the current bail-out, so Codeman never owns an entry it would have to restore on uninstall. Wrapping it would cover more users at the cost of that guarantee.curldid not do.settings.local.json, then projectsettings.json, then the two home files. I derived that from observed behavior rather than from a spec, and I am unsure whether Claude Code reads a user-level~/.claude/settings.local.jsonat all. Getting this wrong means delegating to a command Claude Code itself would have ignored.All reactions