feat: first-run UX with built-in agent profiles#10
Conversation
When a known agent (claude, opencode, etc.) is run without a template, prompt the user to apply recommended filesystem defaults. Each agent is a self-contained file under internal/profiles/agents/ that self-registers via init(), so adding a new agent requires zero changes elsewhere.
…lities Move toolchain commands (npm, uv, cargo, docker, etc.) out of the ad-hoc command set into their own profiles under internal/profiles/toolchains/. Each toolchain is a self-contained file with filesystem paths from the agent-safehouse analysis. Toolchain profiles are not merged with BaseProfile() since they only need their own config/cache directories.
First-run prompt redesign: - Explain that the command is being sandboxed and a profile is available - Show full allow/deny paths with ~/ prefixes for clarity - Add [e] Edit first option with $EDITOR and re-validate loop - Use [s] Skip / [n] Don't ask again instead of [n] / [never] - Add (recommended) and (restrictive) hints on options - ANSI colors when output is a terminal, respects NO_COLOR Template composability: - --template now accepts comma-separated names (e.g. --template claude,python) - Each name resolves: saved template on disk > built-in profile - templates list shows combo usage example README: add Agent profiles section with first-run and --template examples.
Update paths to show ~/ prefix and use current option keys ([s] Skip, [n] Don't ask again, (recommended) hint).
When set, silently applies the built-in profile (or saved template) for known agents without prompting. Useful for CI/scripts where there is no terminal. In non-interactive mode, a hint about --auto-profile is now shown when a built-in profile is available but not applied.
…files Unify terminology: everything is now "profiles" in the CLI and user-facing messages. The old --template flag and "templates" subcommand are kept as hidden aliases for backwards compatibility.
internal/profiles/agents/claude.go
Outdated
| Filesystem: config.FilesystemConfig{ | ||
| AllowRead: []string{ | ||
| "~/.claude", | ||
| "~/.claude.json", | ||
| "~/.claude.json.*", | ||
| "~/.config/claude", | ||
| "~/.local/share/claude", | ||
| "~/.local/state/claude", | ||
| "~/.mcp.json", | ||
| }, | ||
| AllowWrite: []string{ | ||
| "~/.claude", | ||
| "~/.claude.json", | ||
| "~/.claude.lock", | ||
| "~/.cache/claude", | ||
| "~/.config/claude", | ||
| "~/.local/state/claude", | ||
| "~/.local/share/claude", | ||
| "~/.mcp.json", | ||
| }, |
There was a problem hiding this comment.
I found that Claude makes frequent use of the temp directory, which on osx is /private/tmp/, without it many of the tool calls would fail. Worth adding maybe?
Sidenote: Should default templates be os-specific?
There was a problem hiding this comment.
Right, claude is not the /tmp, but /tmp/claude-xxx no ?
I feel showing the whole /tmp could be dangerous as many application leave some socket in it
I will do another pass for the os-specific - maybe i got them lost during internal refactoring.
There was a problem hiding this comment.
@elo-siema actually, i wonder if greywall could redirect the TMPDIR env to be local and deleted when done, that would prevent giving wide access. What do you think?
There was a problem hiding this comment.
Yup, TMPDIR redirection sounds the cleanest, agreed
There was a problem hiding this comment.
/tmp/claude-xxx
yes, but that xxx was unpredictable. Agreed on fishyness of sharing whole tmp
Profiles previously only included XDG/Linux paths. On macOS, agents and toolchains store config, cache, and state under ~/Library/ and /Library/ which were missing entirely. Add runtime.GOOS == "darwin" checks to conditionally include: - Base: keychain paths, user preferences - Agents: Claude Desktop config, Codex plists, Cursor/Cline/Kilo VS Code globalStorage, Goose/Gemini Library paths, Pi metadata - Toolchains: Playwright/Cypress caches (node), JVM paths (java), system Ruby, OrbStack/Colima/Rancher Desktop (containers)
Summary
internal/profiles/agents/andinternal/profiles/toolchains/, each self-contained (add an agent = add one file)[Y]use,[e]edit in $EDITOR,[s]skip,[n]don't ask again--profileaccepts comma-separated names to combine profiles (e.g.--profile claude,python)NO_COLOR~/.config/greywall/preferences.jsonfor "don't ask again"--auto-profileflag: silently applies the built-in profile without prompting (useful for CI/scripts). In non-interactive mode, hints about--auto-profilewhen a profile is available.templatestoprofiles, and same in other placesCloses #9
Test plan
greywall -- claudewith no config prompts,Ysaves profile, agent startsgreywall -- curl https://example.comno prompt (ad-hoc command)echo | greywall -- claudeno prompt (not a terminal)nsuppresses future promptseopens $EDITOR, validates on save, re-edit loop on errors--profile claude,pythonmerges both profilesgreywall profiles listshows saved + available built-in profilesmake testpasses