Permission modes
PermissionMode
Section titled “PermissionMode”ActiveCli.Session.PermissionMode — how much a session may do without asking first. A closed set of named modes rather than a string, because each one has to survive two translations — into the flag a CLI is spawned with, and back out of what the CLI reports about itself — and a bare string would let them drift apart silently.
class PermissionMode { static readonly PLAN: PermissionMode; static readonly ASK_BEFORE_EDIT: PermissionMode; static readonly AUTO_EDIT: PermissionMode; static readonly AUTO: PermissionMode; static readonly BYPASS: PermissionMode;
readonly name: string;
static named(name: string | undefined | null): PermissionMode | null; toString(): string;}| Mode | name |
Meaning |
|---|---|---|
PLAN |
plan |
Plan only: propose, never edit. |
ASK_BEFORE_EDIT |
ask_before_edit |
Ask before every edit. |
AUTO_EDIT |
auto_edit |
Edits go through; other tools still ask. |
AUTO |
auto |
Decide autonomously. |
BYPASS |
bypass |
Ask for nothing at all. |
The constructor is private, so no sixth mode can appear that the adapters do not know how to spell. named() answers null for anything outside the set.
PermissionMode.PLAN // propose, never editPermissionMode.ASK_BEFORE_EDIT // ask before every editPermissionMode.AUTO_EDIT // edits go through; other tools still askPermissionMode.AUTO // decide autonomouslyPermissionMode.BYPASS // ask for nothing
PermissionMode.named('plan'); // => PermissionMode.PLANPermissionMode.named('nonsense'); // => nullClaudePermissionFlag
Section titled “ClaudePermissionFlag”ActiveCli.Adapter.Claude.ClaudePermissionFlag — translates between PermissionMode and the flag names the Claude CLI uses for the same idea.
class ClaudePermissionFlag { forMode(mode: PermissionMode): string; toMode(flag: string | undefined | null): PermissionMode | null;}PermissionMode |
CLI flag |
|---|---|
PLAN |
plan |
ASK_BEFORE_EDIT |
default |
AUTO_EDIT |
acceptEdits |
AUTO |
auto |
BYPASS |
bypassPermissions |
Both directions are needed and must agree: we spawn with the flag, and the CLI then announces its mode using that same vocabulary — on system/init at spawn, and again on system/status when it changes the mode itself. The reverse map is derived from the forward one, which is what keeps the two from drifting.
Note that default names the ask-before-edits mode — it does not mean “follow the user’s settings”, which is why ClaudeArgv omits the flag entirely when no mode is established. Passing --permission-mode default would override the user’s configured setting rather than defer to it.
ModeChange
Section titled “ModeChange”ActiveCli.Session.ModeChange — decides whether a running CLI can serve a request, or has to be restarted.
class ModeChange { constructor(liveMode: PermissionMode | null); requiresRestart(requested: PermissionMode | null | undefined): boolean;}--permission-mode is a spawn-time flag, and no documented command changes it in place. Honouring a mode change mid-conversation therefore means killing the CLI and spawning it again.
Two cases are easy to get wrong:
| Case | Answer | Why |
|---|---|---|
| No mode requested | false |
Not a mode to compare against. Restarting would tear down a working process to spawn an identical one. |
Live mode unknown (null) |
true |
Happens for a session adopted after a host restart. Reusing gambles on a mode nobody observed, and the losing side is edits under looser permissions than the user chose. |
Reach it through Session.requiresRestartFor() rather than constructing one by hand — the session already tracks the live mode.
if (session.requiresRestartFor(PermissionMode.PLAN)) { session.stop(); session = Session.start( new ClaudeAdapter(), new SpawnOptions({ workingDirectory, sessionId, resume: true, permissionMode: PermissionMode.PLAN }), );}Through Command none of this needs handling by hand: setPermissions() records the intent and the next send() respawns if it has to.