Control
How the profile + capability system works, and the full CLI control surface — flags, env vars, config files, slash commands.
How it works
Erosolar is a single binary with a profile selection at startup. The profile picks the system prompt, the default model, and — most importantly — the tool inventory the agent sees. There are three profiles:
Default coding agent. Tool inventory: filesystem (Read / Write / Edit), Bash, Glob/Grep, Web (fetch + search), HITL, TodoWrite, Memory, Skills, Notebook, Worktree, PlanMode, Monitor, Schedule, Trigger, AskUserQuestion / PushNotification, MCP. Same shape as Claude Code with a few additions.
Authorized variant-discovery / exploit-research. Adds Kali wrappers (sqlmap, gobuster, ffuf, hydra, john, hashcat, masscan, etc.), AFL++ fuzzing, gdb / pwndbg triage, pwntools, binary analysis (objdump, readelf, radare2, checksec), Ghidra headless. Terminal phase is coordinated disclosure.
Same offsec capability surface as variant-research. Differs in the terminal phase: requires an active engagement record (USG contract / task-order / defense-prime engagement / published bug-bounty program) at phase.intake; refuses to advance without one.
Capability gating is enforced in code. The default coding profile cannot load offsec tools — even if a configured MCP server tries to surface them. The hardening tests at test/v1.5-capability-gating.test.ts + test/capability-separation.test.ts fail CI on any regression.
Selecting a profile
Two ways, in priority order:
erosolar --profile variant-research # explicit flag EROSOLAR_PROFILE=variant-research erosolar # env var erosolar # default → erosolar-code
Per-profile env overrides
Each profile has its own env namespace formed by uppercasing the profile name. Override the model, provider, or system prompt without recompiling:
| Variable | Effect |
|---|---|
| EROSOLAR_CODE_MODEL | Override default model for the coding profile. |
| EROSOLAR_CODE_PROVIDER | Override default provider (anthropic / openai / deepseek / google / xai / ollama / qwen). |
| EROSOLAR_CODE_SYSTEM_PROMPT | Replace the system prompt entirely (rulebook still loads). |
| VARIANT_RESEARCH_MODEL | Same, for the offsec variant-research profile. |
| ENGAGEMENT_DELIVERY_MODEL | Same, for the engagement-delivery profile. |
If the model env hints at a different provider than the explicit provider env, the model wins. The CLI emits a "modelLocked" / "providerLocked" status badge so it's visible in /status.
Slash commands
In-session control. Top of the inventory:
| Command | Use |
|---|---|
| /model | Pick model + reasoning effort. |
| /approvals | Configure what runs without confirmation (per-tool). |
| /tools | Toggle individual tool suites on / off. |
| /mcp | Inspect / reconnect configured MCP servers. |
| /skills | Browse skills loaded from .erosolar/skills/. |
| /secrets | Set / unset API keys (DeepSeek, Anthropic, Tavily, etc.) in the OS keychain. |
| /thinking | Set extended-thinking depth. |
| /status | Show profile, model, provider, balance, locked state. |
| /doctor | Run startup health checks (auth, model, balance, hooks, MCP). |
| /checks | Run validation suite against the current workspace. |
| /review | Review staged changes / current branch. |
| /diff | Show pending diff. |
| /init | Generate AGENTS.md / CLAUDE.md-equivalent for this repo. |
| /compact | Summarize the conversation to free context. |
| /new | Start a fresh session in the same shell. |
| /undo | Roll back the last agent-applied change. |
| /refresh-models | Re-discover available models from each provider. |
| /features | List active feature flags. |
| /evolve | Run the self-improvement / regression-watch loop. |
| /test | Run the project's test command. |
| /help | Full slash-command list (44 commands). |
| /logout · /quit · /exit | Session controls. |
Config files (project-local under .erosolar/)
| Path | Purpose |
|---|---|
| .erosolar/settings.json | Hooks (PreToolUse / PostToolUse / SessionStart / Stop / UserPromptSubmit) + tool toggles. Same shape as Claude Code's settings.json. |
| .erosolar/mcp.json | MCP servers. Each server can declare a profiles: [...] allow-list — server tools surface only for matching profiles. |
| .erosolar/skills/<name>/SKILL.md | Reusable playbook the agent can invoke. |
| .erosolar/memory/ | Persistent memory across sessions. |
| .erosolar/cron.json | Local cron entries. Mirrored to Firestore via Lambda cliCronUpsert when authenticated; the EventBridge tick fires matching entries server-side. |
| .erosolar/triggers/<id>.json | RemoteTrigger drop files. The webhook relay (POST /api/cliWebhook) writes here via Firestore. |
| .erosolar/plans/<id>.json | EnterPlanMode persistence. |
| .erosolar/worktrees/<id>/ | Live worktrees created by EnterWorktree. |
| ~/.erosolar/auth.json | Firebase ID token + refresh token. Mode 0600. Used by all Lambda calls. |
MCP server tenant-mount example
An offsec MCP server that should only mount for the variant-research / engagement-delivery profiles:
{
"mcpServers": {
"kali-server": {
"command": "npx",
"args": ["-y", "@modelcontextprotocol/server-mcp-kali-server"],
"profiles": ["variant-research", "engagement-delivery"]
},
"github": {
"command": "npx",
"args": ["-y", "@modelcontextprotocol/server-github"]
}
}
}
The github server has no profiles field — it mounts for all profiles (back-compat default). The kali-server only surfaces for the offsec profiles, so a default coding session never sees its tools even if the config is present.
Hooks
Shell-command hooks fire around tool execution and session lifecycle. Same contract as Claude Code: the command receives a JSON envelope on stdin, can pass through, block, or shape the result via JSON on stdout. Configured in .erosolar/settings.json:
{
"hooks": {
"PreToolUse": [
{ "matcher": "Bash",
"hooks": [{ "type": "command", "command": "/path/to/audit-bash.sh" }] }
],
"PostToolUse": [
{ "matcher": "Edit|Write",
"hooks": [{ "type": "command", "command": "/path/to/lint-after-edit.sh" }] }
],
"SessionStart": [
{ "hooks": [{ "type": "command", "command": "/path/to/session-banner.sh" }] }
]
}
}
Hooks are best-effort: timeout / error / malformed JSON is logged and skipped, never crashes the agent.
Diagnostic env vars
| Variable | Effect |
|---|---|
| EROSOLAR_DEBUG=1 | Verbose debug logging. |
| EROSOLAR_INK_DEBUG=1 | Ink (terminal UI) trace logging. |
| EROSOLAR_PLAIN_OUTPUT=1 | Force plain output mode (no colour, no Ink). Useful for CI / pipes. |
| EROSOLAR_DISABLE_PORTAL_HITL=1 | Skip the portal HITL bridge for AskUserQuestion in non-TTY runs (returns "cancelled" instantly). |
| EROSOLAR_AGENT_RUN_TIMEOUT_MS=<ms> | Per-turn agent timeout (default unbounded). |
| EROSOLAR_PRESERVE_HOME=1 | Don't sandbox $HOME for Bash tool invocations. |
| EROSOLAR_INK=0 | Disable Ink renderer (force readline shell). |
| EROSOLAR_DISABLE_PROJECT_REGISTRATION=1 | Skip the projects-rendezvous fire-and-forget call at session start. |
| EROSOLAR_ENABLE_PROJECT_REGISTRATION=1 | Opt-in: register offsec-profile sessions to the portal projects list (with host + owner masked). |
erosolar-code) will not load offsec tools at runtime, will not surface offsec MCP servers, and will not load the offsec system-prompt addendum — by design. If you need both surfaces in one session, switch profiles; don't try to merge them. See the rationale in CLAUDE.md "Capability separation" + the v1.5 hardening test.