You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Adding a secondary user post-install currently requires several manual steps the operator must execute correctly and in order. The most recent secondary-user onboarding surfaced multiple sharp edges, most of which have since been mitigated. A wizard would centralize the remaining bookkeeping while leaving prerequisites (which need human judgement) to the operator.
Prerequisites (operator handles before running wizard)
These steps inherently require human action and stay outside the wizard's scope:
macOS user account exists (sysadminctl -addUser <name> or System Settings).
Operator has logged in once as that OS user and run claude to populate that user's ~/.claude.json with OAuth tokens.
Operator knows the new user's Telegram chat_id, intended role, and any per-user defaults they want to set.
Proposed flow
sudo make add-user
The wizard:
Prompts for required fields: telegram_id, name, os_user, role, github (optional).
Prompts for per-user defaults with sensible inherited fallbacks: workspace_base, model, agent_backend, max_budget.
Prompts for optional GitHub routing: github_repos, github_notify_chat_id, pr_review, issue_triage.
Creates DATA_DIR/memory/<chat_id>/ and DATA_DIR/history/<chat_id>/ as the service identity, then chown to the target uid/gid.
Seeds MEMORY.md from the tracked MEMORY.md.example.
Smoke test: writes and removes a sentinel file as the target user via sudo -H -u <os_user>, surfacing permission errors immediately rather than at first message.
Reminds the operator to run sudo launchctl kickstart -k system/<service-label> (or equivalent on Linux) so the running service picks up the new entry.
Why this is needed
The current flow has these traps:
File mode and ownership: subprocess running under a different os_user via sudo -H -u cannot write to dirs created by the service identity. This was the root cause of issue Per-user MEMORY.md under memory/<chat_id>/ #347. Lazy bootstrap fixes it for already-known users at install time but cannot fix post-install additions, because the new dir gets created service-owned the first time the new user sends a message (see ensure_user_memory docstring).
Step-skipping: each manual step (yaml edit, dir creation, chown, seed, restart) has a silent failure mode that only surfaces hours later when the user finally messages the bot.
Validation timing: a typo in os_user or a missing OS account currently surfaces as an opaque mid-stream subprocess failure rather than a wizard prompt.
A wizard that mirrors the existing make config pattern in install._cmd_config() would eliminate these traps without introducing new infrastructure.
Non-goals
Not creating macOS accounts. sysadminctl needs interactive password prompts; this stays outside the wizard.
Not running claude OAuth login for the new user. That requires a browser session as the target user.
Not removing users. A separate remove-user utility could mirror this pattern later.
Not editing install.conf. All tunables stay in the wizard surface, per existing project rule.
Follow-up
Hot-reload users.yaml via SIGHUP #292 (SIGHUP hot-reload of users.yaml) makes the final wizard step a signal rather than a kickstart. After Hot-reload users.yaml via SIGHUP #292 ships, this wizard should be updated to send SIGHUP automatically (with operator confirmation), eliminating the only remaining manual step.
Summary
Adding a secondary user post-install currently requires several manual steps the operator must execute correctly and in order. The most recent secondary-user onboarding surfaced multiple sharp edges, most of which have since been mitigated. A wizard would centralize the remaining bookkeeping while leaving prerequisites (which need human judgement) to the operator.
Prerequisites (operator handles before running wizard)
These steps inherently require human action and stay outside the wizard's scope:
sysadminctl -addUser <name>or System Settings).claudeto populate that user's~/.claude.jsonwith OAuth tokens.Proposed flow
The wizard:
telegram_id,name,os_user,role,github(optional).workspace_base,model,agent_backend,max_budget.github_repos,github_notify_chat_id,pr_review,issue_triage.os_userexists viapwd.getpwnamBEFORE any disk mutation (same pattern as_apply_migratein install.py post-Per-user MEMORY.md under memory/<chat_id>/ #347).users.yamlatomically.DATA_DIR/memory/<chat_id>/andDATA_DIR/history/<chat_id>/as the service identity, thenchownto the target uid/gid.MEMORY.mdfrom the trackedMEMORY.md.example.sudo -H -u <os_user>, surfacing permission errors immediately rather than at first message.sudo launchctl kickstart -k system/<service-label>(or equivalent on Linux) so the running service picks up the new entry.Why this is needed
The current flow has these traps:
os_userviasudo -H -ucannot write to dirs created by the service identity. This was the root cause of issue Per-user MEMORY.md under memory/<chat_id>/ #347. Lazy bootstrap fixes it for already-known users at install time but cannot fix post-install additions, because the new dir gets created service-owned the first time the new user sends a message (seeensure_user_memorydocstring).os_useror a missing OS account currently surfaces as an opaque mid-stream subprocess failure rather than a wizard prompt.A wizard that mirrors the existing
make configpattern ininstall._cmd_config()would eliminate these traps without introducing new infrastructure.Non-goals
sysadminctlneeds interactive password prompts; this stays outside the wizard.claudeOAuth login for the new user. That requires a browser session as the target user.remove-userutility could mirror this pattern later.install.conf. All tunables stay in the wizard surface, per existing project rule.Follow-up
users.yaml) makes the final wizard step a signal rather than a kickstart. After Hot-reload users.yaml via SIGHUP #292 ships, this wizard should be updated to send SIGHUP automatically (with operator confirmation), eliminating the only remaining manual step.Related
pwd.getpwnamvalidate-before-mutate and per-user dir chown patterns this wizard would reuse.