sid-isnt-done 0.3.0

sid is a UNIX-inspired coding agent for Anthropic-compatible APIs
Documentation
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
# SID(1)

## NAME

sid - run a small, rc-configured coding agent in the current workspace

## SYNOPSIS

```text
sid [OPTIONS]
sid --resume SESSION [OPTIONS]
SID_HOME=DIR sid [OPTIONS]
sid --bash-debug COMMAND
sid-seatbelt [--writable-roots DIR[:DIR...]] -- COMMAND [ARG...]
```

Generated help spells long options with one leading dash.  The parser also
accepts the double-dash forms used below.

## DESCRIPTION

`sid` starts an interactive coding-agent session rooted at the current working
directory.  The workspace is mounted for the model's virtual filesystem as `/`;
that virtual mount is not an operating-system chroot.  Agent definitions, tool
definitions, and optional skills are read from rc-style configuration files
rather than from hardcoded tool lists.

When no `sid` configuration exists, `sid` starts the built-in `sid` agent with
no configured external tools.  When `agents.conf` or `tools.conf` exists,
configuration is loaded from `SID_HOME` if it is set and non-empty; otherwise
configuration is loaded from the current directory.

The interactive prompt accepts ordinary user messages and slash commands.  Use
`/help` inside a running session for chat commands such as changing the model,
switching agents, compacting the conversation into a new child session, saving
or loading transcripts, clearing context, and printing session stats.  Use
`--resume <session-id-or-dir>` to reopen an earlier session directory,
reload `transcript.json`, continue appending to the same journals, and restore
the persisted bash shell state for future `bash` tool calls.

## QUICKSTART

Install and initialize:

```sh
cargo install sid-isnt-done
SID_HOME=~/.sid sid-init
```

`sid-init` copies the bundled starter configuration (agents, tools, and
prompts) into `SID_HOME`.  It requires `SID_HOME` to be set.  Files that
already exist are skipped, so it is safe to re-run after upgrading.

Start a session:

```sh
export CLAUDIUS_API_KEY="..."
SID_HOME=~/.sid sid
```

Run one bash command through the configured bash tool and exit:

```sh
SID_HOME=~/.sid sid --bash-debug 'pwd && ls'
```

From a source checkout, you can skip `sid-init` and point `SID_HOME` directly
at the bundled `init/` directory:

```sh
cargo build
SID_HOME=init cargo run --bin sid
SID_HOME=init cargo run --bin sid -- --bash-debug 'pwd && ls'
```

## BUILDING

`sid` is a Rust project using the 2024 edition.  Use Rust 1.94 or newer and the
normal Cargo workflow:

```sh
cargo build
cargo test
cargo install --path .
```

Interactive sessions use the Anthropic client from `claudius`.  Set
`CLAUDIUS_API_KEY` or `ANTHROPIC_API_KEY` before starting `sid`.  Values that
begin with `file://` are treated by `claudius` as paths to files containing the
API key.

macOS is the only platform where `sid` can use `/usr/bin/sandbox-exec`.  On
other systems, or on macOS systems where that program is unavailable, `sid`
runs bash and external tools without the Seatbelt wrapper and prints a startup
warning.

## OPTIONS

`--param-model MODEL`
: Use `MODEL` for the session.  The default is supplied by `claudius` and is
  currently printed by `sid --help`.

`--param-system PROMPT`
: Set the initial system prompt.  Agent prompt files and agent configuration can
  override this value when a configured workspace is loaded.

`--param-max-tokens TOKENS`
: Set the maximum response tokens per model request.

`--param-temperature TEMP`
: Set sampling temperature.  `TEMP` must be between `0.0` and `1.0`.

`--param-top-p TOP_P`
: Set nucleus sampling.  `TOP_P` must be between `0.0` and `1.0`.

`--param-top-k TOP_K`
: Set top-k sampling.

`--param-thinking TOKENS`
: Enable extended thinking with the given token budget.

`--param-no-color`
: Disable ANSI color and style output.

`--bash-debug COMMAND`
: Run `COMMAND` through the configured built-in bash tool and exit.  This is
  useful for checking tool configuration without starting an interactive chat.

`--resume SESSION`
: Resume an existing session by timestamp id or by session directory path.
  Session ids are resolved under `${SID_SESSIONS:-${SID_HOME}/sessions}`.
  Resuming reloads the saved transcript, continues the existing event and API
  journals, preserves ordered tool numbering, and restores the persisted bash
  shell snapshot.

`--help`
: Print the command-line help.

## MODEL SELECTION

The model can be selected at startup with `--param-model MODEL`, configured per
agent with `<agent>_MODEL`, or changed during a session with `/model MODEL`.
Run `sid --help` to see the compiled default model.  Use `/help` inside a
session to see the current chat commands.

`sid` passes model names through to `claudius`; it does not maintain a separate
registry of available model names.  Prefer provider documentation or the
Anthropic models API for the current model list.

## CONFIGURATION

Configuration uses two required files when configuration is present:

```text
agents.conf
tools.conf
```

Agent prompts live in `agents/`.  External tool executables and manifests live
in `tools/`.  Skills live in `skills/<skill>/SKILL.md` unless `SID_SKILLS_PATH`
is set.

The bundled starter configuration is in `init/`:

```sh
SID_HOME=init sid
```

## AGENTS

An agent is an rc-conf service in `agents.conf`.  Service names are discovered
by `rc_conf`; each service may define fields under the service prefix:

```sh
DEFAULT_AGENT="build"

build_ENABLED="YES"
build_NAME="Let's Go"
build_DESC="buildit"
build_TOOLS="bash edit format"
build_SKILLS="*"
build_MODEL="claude-sonnet-4-5"
build_MAX_TOKENS="8192"
build_THINKING="on"
```

`<agent>_ENABLED`
: Controls whether the agent can start.  `YES` starts immediately, `MANUAL`
  asks the operator before starting, and `NO` disables the agent.

`<agent>_NAME`
: Optional display name.

`<agent>_DESC`
: Optional description.

`<agent>_TOOLS`
: Space-split list of configured tool names exposed to the agent.

`<agent>_SKILLS`
: Space-split list of skills to mount.  Use `*` to mount every loaded skill.

`<agent>_MODEL`, `<agent>_SYSTEM`, `<agent>_MAX_TOKENS`
: Optional model, inline system-prompt override, and response-token overrides.

`<agent>_PROMPT`
: Optional colon-separated list of markdown files.  Relative paths are resolved
  under the config root, `~/` expands from `HOME`, all listed files must
  exist, and their contents are concatenated in order with blank lines.  This
  becomes the agent's base system prompt before `<agent>_SYSTEM` overrides are
  applied.

`<agent>_PROMPT_COMPACTION`, `<agent>_PROMPT_MEMORY_EXPERT`
: Optional named prompt bundles resolved the same way as `<agent>_PROMPT`.
  `sid` uses `COMPACTION` for the `/compact` request sent to that agent and
  `MEMORY_EXPERT` for the follow-up addendum used by `ask_an_expert` on
  compacted sessions.  Other `PROMPT_*` keys are ignored by `sid`.

`<agent>_TEMPERATURE`, `<agent>_TOP_P`, `<agent>_TOP_K`
: Optional sampling controls.

`<agent>_STOP_SEQUENCES`
: Space-split stop sequence list.  Shell-style quoting is supported by
  `shvar`.

`<agent>_THINKING`
: `on`, `yes`, or `true` enables the default thinking budget.  A number sets an
  explicit budget.  `off`, `no`, or `false` disables thinking.

`<agent>_USE_COLOR`, `<agent>_NO_COLOR`
: Optional terminal color controls.

`<agent>_SESSION_BUDGET`
: Optional token budget for the session.

`<agent>_CACHING_ENABLED`
: Optional prompt-cache toggle.

`<agent>_USER_INSTRUCTIONS`
: Optional boolean.  Defaults to `YES`.  Set to `NO` to disable automatic
  hook-based user-instruction injection for this agent.

`<agent>_AGENTS_MD`
: Optional boolean.  Defaults to `YES`.  Set to `NO` to disable AGENTS.md file
  injection.

`<agent>_AGENTS_MD_PATH`
: Optional colon-separated list of AGENTS.md files to read.  Relative paths are
  resolved under the workspace root, `~/` expands from `HOME`, missing files are
  skipped, and existing files are concatenated in path order.  Put global files
  before local files so local instructions appear later in the injected
  document with proper context.  If unset, `sid` uses `AGENTS_MD_PATH` from the
  environment, then falls back to `./AGENTS.md`.

`<agent>_USER_INSTRUCTIONS_HOOK`
: Optional rc-conf service name.  `sid` invokes `agents/<service> run` for each
  user turn and appends the hook's standard output to the injected user
  instructions.  The executable must answer `rcvar` and `run`.

If `<agent>_PROMPT` is unset, the prompt file for an agent is
`agents/<agent>.md`.  If the agent is an alias, `sid` follows the rc-conf
alias lookup order and uses the first matching prompt file.  Prompt-file
content becomes the agent's system prompt unless overridden by
`<agent>_SYSTEM`.

If `DEFAULT_AGENT` is unset, `sid` starts the first enabled agent.  If no agent
is enabled, it starts the first manual agent after confirmation.

Within an interactive session, `sid` can hand work from one configured agent to
another without restarting:

```text
/compact
/agent
/agent list
/agent switch <name>
```

The active transcript, session journals, and persisted bash state remain tied
to the same `sid` session directory.  Explicit runtime overrides such as
`/model`, `/temperature`, `/stop`, `/thinking`, `/budget`, and `/cache` remain
in effect after an agent switch until they are changed again.

`/compact` runs the reserved `compact` agent when it is configured in
`agents.conf`; otherwise `sid` uses a built-in compaction prompt.  The command
creates a new child session whose initial transcript is a summary of the prior
session.  Set `compact_PROMPT_COMPACTION` to override the request sent to the
compactor and `compact_PROMPT_MEMORY_EXPERT` to override the follow-up memory
mode prompt captured into compacted-session provenance.  Compacted sessions
expose an `ask_an_expert` tool that can consult the earlier summary writer by
contextual memory.

## USER INSTRUCTIONS

User instructions are dynamically appended as a final text block on each user
turn before `sid` sends the turn to the model.  The saved conversation history
is remains after the turn, so that caching works and the agent always has proper
context on the things to which they pay attention.

Hook output is wrapped under `# User instructions from hook <name>`.  Direct
system and operator instructions take precedence over these injected user
instructions.

A hook is an rc-style executable in `agents/`.  It uses `agents.conf` plus a
per-invocation overlay and receives `RC_CONF_PATH`, `RC_D_PATH`, `RCVAR_ARGV0`,
and any rcvars it advertises.  Common advertised variables are:

```text
<hook>_WORKSPACE_ROOT
<hook>_CONFIG_ROOT
<hook>_AGENT_ID
<hook>_HOOK_NAME
<hook>_AGENTS_MD_PATH
<hook>_USER_MESSAGE_FILE
<hook>_SKILLS_MANIFEST_FILE
<hook>_SKILLS_DIR
<hook>_SCRATCH_DIR
<hook>_TEMP_DIR
<hook>_TMPDIR
<hook>_RC_CONF_PATH
<hook>_RC_D_PATH
```

Example hook:

```sh
#!/bin/sh
set -eu

PREFIX=${RCVAR_ARGV0:?missing RCVAR_ARGV0}

case "${1:-}" in
rcvar)
    printf '%s\n' \
        "${PREFIX}_WORKSPACE_ROOT" \
        "${PREFIX}_AGENT_ID"
    ;;
run)
    WORKSPACE_ROOT=$(printenv "${PREFIX}_WORKSPACE_ROOT")
    AGENT_ID=$(printenv "${PREFIX}_AGENT_ID")
    printf 'Agent %s is working in %s\n' "$AGENT_ID" "$WORKSPACE_ROOT"
    ;;
*)
    echo "usage: $0 [rcvar|run]" >&2
    exit 129
    ;;
esac
```

## SKILLS

Skills are markdown documents mounted read-only into the model-visible virtual
filesystem.  By default, `sid` scans:

```text
skills/<skill>/SKILL.md
```

Set `SID_SKILLS_PATH` to a colon-separated list of directories to load skills
from somewhere else.  Each directory in the path is scanned for immediate
children containing `SKILL.md`.  If two directories provide the same skill id,
the earlier directory wins.

Expose skills to an agent with `<agent>_SKILLS`:

```sh
build_SKILLS="rust-style release-checklist"
```

Use `*` to expose every loaded skill:

```sh
build_SKILLS="*"
```

A skill should be self-contained markdown that tells the model when to use it
and what procedure to follow.  Keep skill ids stable and filesystem-friendly;
the document is mounted for the model at `/skills/<skill>/SKILL.md`.  Bash and
external tools do not see this virtual `/skills` mount.

The bundled `skill-inject` user-instructions hook delegates to
`sid-skill-inject`.  Enable it with `<agent>_USER_INSTRUCTIONS_HOOK` and mention
an exposed skill as `$skill-id` in a user prompt to append a Codex-style block
to that turn:

```xml
<skill>
<name>skill-id</name>
<path>/skills/skill-id/SKILL.md</path>
...skill markdown...
</skill>
```

Custom hooks can symlink to `sid-skill-inject` or `exec sid-skill-inject "$@"`
to reuse the same `$skill-id` parsing and block rendering.  The
`sid-skill-inject` binary must be on the hook process's `PATH`.

## TOOLS

Tools are rc-conf services in `tools.conf`.  There are no implicit external
tools: a tool named by an agent must also be defined in `tools.conf`.
Canonical tool ids and model-visible external tool names must be 1-64 ASCII
letters, digits, underscores, or hyphens.

```sh
bash_ENABLED="MANUAL"
edit_ENABLED="MANUAL"
edit_CONFIRM="YES"
fmt_ENABLED="MANUAL"
fmt_CONFIRM="YES"

format_INHERIT="YES"
format_ALIASES="fmt"
```

`<tool>_ENABLED`
: Controls whether the tool can be used.  `YES` allows calls, `MANUAL` prompts
  the operator for every call, and `NO` disables the tool.

`<tool>_ALIASES`
: Defines aliases resolved before filesystem lookup.  In the example above,
  `format` resolves to canonical tool `fmt`.

`<tool>_CONFIRM`
: Optional boolean.  When `YES` and the tool is `MANUAL`, `sid` invokes
  `tools/<id> confirm` before the host-owned yes/no prompt.  The confirm
  subcommand renders a preview to standard output; it does not authorize the
  call and must not perform the tool operation.  The starter `edit` tool keeps
  `view` previews compact, but mutating editor commands render a file summary
  plus a diff preview.  Set `DIFF` to a shell command to filter that unified
  diff, or set `DIFF` empty to show the raw unified diff text.

`<tool>_PROMPT`
: Optional colon-separated markdown bundle resolved under the config root and
  concatenated in order.  `sid` loads it into tool config metadata.  Other
  prompt-shaped tool variables remain available to your rc-style tool scripts,
  but `sid` does not ingest them unless they become host-owned keys.

`bash`
: Built-in bash capability.  It is exposed to the model as Anthropic's bash
  tool.  It runs in the host filesystem namespace, not a chroot.  The initial
  working directory is the workspace root; host `/` remains visible subject to
  normal OS permissions and the optional macOS Seatbelt policy.  It does not
  need a `tools/bash` executable or `tools/bash.json` manifest.

`edit`
: Built-in text-editor capability.  It is exposed to the model as Anthropic's
  text editor tool, but calls are routed through `tools/edit`; the starter
  script execs `sid-editor-tool`.  The helper process is not chrooted, but the
  editor protocol resolves file paths under `WORKSPACE_ROOT`; `/etc/passwd` in
  an editor request means `$WORKSPACE_ROOT/etc/passwd`, not host `/etc/passwd`.
  `tools/edit` must exist and be executable when `edit` is configured.  A
  `tools/edit.json` manifest is optional because the model-visible schema comes
  from the built-in Anthropic text-editor tool definition.

`read`
: Read a file or a line range from the workspace.  This is a narrower,
  read-only alternative to the editor's `view` command.  The starter
  `tools/read` script delegates to `sid-editor-tool --readonly`.  It accepts
  `path`, and optional `start_line`/`end_line` parameters (1-indexed,
  inclusive; `-1` means end of file).  Output includes line numbers.
  Directories are listed instead of read.  Enabled `YES` by default because
  it is read-only.

`search`
: Search the workspace for a pattern using ripgrep.  Returns matching lines with
  file paths and line numbers.  Accepts `pattern` (regex by default),
  optional `path` to restrict scope, `fixed_strings` for literal matching,
  `include` for glob-based file filtering, and `max_results` (default 200).
  Enabled `YES` by default because it is read-only.

`glob`
: List workspace files matching a glob pattern.  Accepts `pattern` (e.g.
  `*.rs`, `Cargo.*`) and optional `path` to restrict to a subdirectory.
  Ignores `.git`, `node_modules`, and `target` directories.  Enabled `YES`
  by default because it is read-only.

`git_status`
: Show the working tree status of the git repository.  Accepts an optional
  `short` boolean for `--short` format.  Enabled `YES` by default because
  it is read-only.

`git_diff`
: Show changes in the git working tree or between commits.  Accepts optional
  `staged` boolean for `--cached`, `path` to restrict scope, and `ref` to
  diff against a specific commit or branch.  Enabled `YES` by default because
  it is read-only.

External tools must provide both files below for the canonical tool id:

```text
tools/<id>
tools/<id>.json
```

The executable must be marked executable.  The manifest supplies the model
description and input schema:

```json
{
  "protocol_version": 1,
  "description": "Format source files in the workspace.",
  "input_schema": {
    "type": "object",
    "properties": {
      "paths": {
        "type": "array",
        "items": { "type": "string" }
      }
    },
    "required": ["paths"]
  }
}
```

Manifest rules:

- `protocol_version` is required and must be `1`.
- `description` is required and must not be empty.
- `input_schema` is required and must be a JSON object.
- The manifest does not contain the tool name.

The model-visible name is the name listed in `<agent>_TOOLS`, not necessarily
the canonical id.  Thus `format` can resolve to canonical executable `tools/fmt`
while still appearing to the model as `format`.

## TOOL PROTOCOL

Tool executables are rc-style programs.  They must respond to `rcvar` and
`run`; they may also respond to `confirm` for manual-call previews.

```sh
#!/bin/sh
set -eu

PREFIX=${RCVAR_ARGV0:?missing RCVAR_ARGV0}

case "${1:-}" in
rcvar)
    printf '%s\n' \
        "${PREFIX}_REQUEST_FILE" \
        "${PREFIX}_RESULT_FILE" \
        "${PREFIX}_SCRATCH_DIR" \
        "${PREFIX}_TEMP_DIR" \
        "${PREFIX}_TMPDIR" \
        "${PREFIX}_WORKSPACE_ROOT" \
        "${PREFIX}_AGENT_ID" \
        "${PREFIX}_TOOL_ID" \
        "${PREFIX}_TOOL_NAME" \
        "${PREFIX}_TOOL_PROTOCOL" \
        "${PREFIX}_RC_CONF_PATH" \
        "${PREFIX}_RC_D_PATH"
    ;;
confirm)
    export REQUEST_FILE=$(printenv "${PREFIX}_REQUEST_FILE")
    export WORKSPACE_ROOT=$(printenv "${PREFIX}_WORKSPACE_ROOT")
    printf 'Format paths from %s under %s\n' "$REQUEST_FILE" "$WORKSPACE_ROOT"
    ;;
run)
    export REQUEST_FILE=$(printenv "${PREFIX}_REQUEST_FILE")
    export RESULT_FILE=$(printenv "${PREFIX}_RESULT_FILE")
    export TMPDIR=$(printenv "${PREFIX}_TMPDIR")
    export WORKSPACE_ROOT=$(printenv "${PREFIX}_WORKSPACE_ROOT")
    exec ./tools/fmt.impl
    ;;
*)
    echo "usage: $0 [rcvar|confirm|run]" >&2
    exit 129
    ;;
esac
```

Each `sid` process creates a timestamp-named session directory under
`${SID_SESSIONS:-${SID_HOME}/sessions}`, for example
`2026-04-20T18-42-13.123456-0700`.  Durable session state is written to a small
set of append-only journals plus a bash snapshot file:

```text
session.json
transcript.json
events.jsonl
api.jsonl
tool-streams.jsonl
bash-state.sh
```

Starting `sid --resume <session>` reuses that directory instead of creating a
new one.  `sid` reloads `transcript.json`, appends a `session_resume` record to
`events.jsonl`, continues `api.jsonl` and ordered tool sequences, and restores
`bash-state.sh` into the next fresh PTY-backed bash session.

Running `/compact` creates a fresh session directory instead of mutating the
current one.  The new `session.json` records which prior session it came from
plus the prompt/model snapshot for the summary writer so future
`ask_an_expert` calls can recurse through older compacted sessions.

For each tool call, `sid` creates a fresh ordered runtime directory under
`<session>/tmp/tool-000001/`, writes `request.json`, writes an rc-conf overlay,
invokes `tools/<id> run`, reads `result.json`, appends lifecycle and stream
records to the session journals, then deletes the runtime directory by default.
The tool process runs with the workspace root as its current directory,
receives a per-invocation `TMPDIR`, and inherits standard input, standard
output, and standard error.  Tool processes are not chrooted; host `/` is still
the process root unless the operating system or sandbox policy denies a
particular operation.

For `MANUAL` tools with `<tool>_CONFIRM=YES`, `sid` prepares the same request
and overlay, invokes `tools/<id> confirm`, captures its stdout as preview text,
appends confirmation output to `tool-streams.jsonl`, then asks the operator for
yes/no itself.  If preview rendering fails, `sid` falls back to showing the raw
request JSON.  The real `run` subcommand is not invoked unless the operator
approves.

The request file has this shape:

```json
{
  "protocol_version": 1,
  "request_id": "sidreq_123",
  "tool": {
    "id": "fmt"
  },
  "invocation": {
    "tool_use_id": "toolu_abc",
    "input": {
      "paths": ["src/lib.rs"]
    }
  },
  "agent": {
    "id": "build"
  },
  "workspace": {
    "root": "/abs/workspace",
    "cwd": "/abs/workspace"
  },
  "files": {
    "scratch_dir": "/sid/sessions/2026-04-20T18-42-13.123456-0700/tmp/tool-000001",
    "temp_dir": "/sid/sessions/2026-04-20T18-42-13.123456-0700/tmp/tool-000001/tmp",
    "result_file": "/sid/sessions/2026-04-20T18-42-13.123456-0700/tmp/tool-000001/result.json"
  }
}
```

A successful result is:

```json
{
  "protocol_version": 1,
  "request_id": "sidreq_123",
  "ok": true,
  "output": {
    "kind": "text",
    "text": "Formatted 3 files."
  }
}
```

A handled failure is:

```json
{
  "protocol_version": 1,
  "request_id": "sidreq_123",
  "ok": false,
  "error": {
    "code": "invalid_input",
    "message": "paths must not be empty"
  }
}
```

Protocol rules:

- During `confirm`, standard output is the human-readable preview.
- During `run`, standard output and standard error are for the human terminal.
- When a session is active, `confirm`, `stdout`, and `stderr` bytes are copied
  into `tool-streams.jsonl`.  Non-UTF-8 chunks are stored as base64.
- During `run`, `sid` only parses `result.json`.
- Exit status `0` means process transport succeeded, so `result.json` must
  exist and be valid.
- Nonzero exit status is treated as process failure; any partial result file is
  ignored.
- `request_id` in the result must match the request.
- Protocol v1 output is text-only.
- Runtime tool scratch is deleted after the invocation unless a debug keep
  environment variable is set.

## ENVIRONMENT

`SID_HOME`
: Configuration root.  If unset or empty, the current working directory is
  used.

`SID_SESSIONS`
: Session directory root.  If unset or empty, `sid` stores sessions under
  `${SID_HOME}/sessions`.

`SID_SESSION_ID`
: Timestamp session id for the current `sid` process.  Set by `sid` for child
  processes.

`SID_SESSION_DIR`
: Absolute or configured path to the current session directory.  Set by `sid`
  for child processes.

`SID_KEEP_TOOL_SCRATCH`
: Set to `1`, `true`, `yes`, or `on` to preserve per-tool runtime directories
  under `<session>/tmp/` after invocations.

`SID_KEEP_FAILED_TOOL_SCRATCH`
: Set to `1`, `true`, `yes`, or `on` to preserve per-tool runtime directories
  only for failed invocations.

`SID_SKILLS_PATH`
: Colon-separated list of directories to scan for `*/SKILL.md`.  If unset,
  `sid` scans `skills/` under the configuration root.

`<hook>_USER_MESSAGE_FILE`
: Per-turn user-instructions hook rcvar containing a scratch file with the
  current user message text.

`<hook>_SKILLS_MANIFEST_FILE`
: Per-turn user-instructions hook rcvar containing a tab-separated manifest of
  exposed, `$mention`-invocable skills.  Each row is
  `skill-id<TAB>/skills/<skill-id>/SKILL.md<TAB>scratch-content-file`.

`<hook>_SKILLS_DIR`
: Per-turn user-instructions hook rcvar containing the scratch directory that
  holds skill content files referenced by `<hook>_SKILLS_MANIFEST_FILE`.

`AGENTS_MD_PATH`
: Colon-separated list of AGENTS.md files to inject when
  `<agent>_AGENTS_MD_PATH` is unset.  Relative paths are resolved under the
  workspace root.  Files are concatenated in order, so list global files before
  local files if you desire that.  If both are unset, `sid` checks `./AGENTS.md`.

`SID_WORKSPACE_ROOT`
: Set by `sid` for child processes to the absolute workspace root.

`RCVAR_ARGV0`
: Set during tool invocation to the invoked tool name rendered as an rc
  variable prefix.

`RC_CONF_PATH`
: Set during tool invocation to
  `<config-root>/tools.conf:<session>/tmp/tool-000001/tool-invoke.conf`.

`RC_D_PATH`
: Set during tool invocation to `<config-root>/tools`.

For each configured tool service, the overlay binds these variables under that
service's prefix:

```text
<tool>_REQUEST_FILE
<tool>_RESULT_FILE
<tool>_SCRATCH_DIR
<tool>_TEMP_DIR
<tool>_TMPDIR
<tool>_WORKSPACE_ROOT
<tool>_SESSION_ID
<tool>_SESSION_DIR
<tool>_AGENT_ID
<tool>_TOOL_ID
<tool>_TOOL_NAME
<tool>_TOOL_PROTOCOL
<tool>_RC_CONF_PATH
<tool>_RC_D_PATH
```

Aliases get their own prefix.  If the model invokes `format`, the tool reads
`format_REQUEST_FILE`; if it invokes `fmt`, it reads `fmt_REQUEST_FILE`.

## SANDBOXING

On macOS, `sid` wraps bash and external tool processes with
`/usr/bin/sandbox-exec` when it is available.  This is a sandbox wrapper, not a
chroot: processes still see host `/`.  The generated policy allows reads from
the workspace, session scratch, temporary directories, `~/src`, `~/.cargo`,
`~/.rustup`, common Git config locations under `$HOME`, and
`/Library/Developer/CommandLineTools`; and, writes to the workspace, session
directory, and system temporary directory, and loopback networking.  On
systems without `sandbox-exec`, commands run without this wrapper.

`sid-seatbelt` is a helper for running an arbitrary command under the same
macOS Seatbelt policy:

```sh
sid-seatbelt --writable-roots "$PWD:/tmp" -- make test
```

## FILES

`agents.conf`
: Agent services and default-agent selection.

`agents/<agent>.md`
: Agent prompt markdown.

`tools.conf`
: Tool services, enable states, and aliases.

`tools/<id>`
: Rc-style executable for an external tool or the `edit` bridge.

`tools/<id>.json`
: Tool manifest for model-visible external tools.

`skills/<skill>/SKILL.md`
: Optional skill document mounted read-only under `/skills/<skill>/`.

`${SID_SESSIONS:-${SID_HOME}/sessions}/${SID_SESSION_ID}/session.json`
: Session metadata with the timestamp id, ISO-like creation time,
  microsecond Unix timestamp, and process id.

`${SID_SESSIONS:-${SID_HOME}/sessions}/${SID_SESSION_ID}/transcript.json`
: Auto-saved chat transcript.

`${SID_SESSIONS:-${SID_HOME}/sessions}/${SID_SESSION_ID}/events.jsonl`
: Session and tool lifecycle journal.

`${SID_SESSIONS:-${SID_HOME}/sessions}/${SID_SESSION_ID}/api.jsonl`
: Ordered API request and response payload journal.

`${SID_SESSIONS:-${SID_HOME}/sessions}/${SID_SESSION_ID}/tool-streams.jsonl`
: Tool confirmation, stdout, and stderr stream journal.

`${SID_SESSIONS:-${SID_HOME}/sessions}/${SID_SESSION_ID}/bash-state.sh`
: Restorable bash shell snapshot used when a session is resumed.

`${SID_SESSIONS:-${SID_HOME}/sessions}/${SID_SESSION_ID}/tmp/`
: Runtime scratch.  Tool directories and bash temporary files live here while
  needed and are cleaned by default.

## TROUBLESHOOTING

`API key not provided and ANTHROPIC_API_KEY environment variable not set`
: Set `CLAUDIUS_API_KEY` or `ANTHROPIC_API_KEY` before starting `sid`.

`agent references an undefined tool`
: The agent listed a name in `<agent>_TOOLS` that does not have a matching
  service in `tools.conf`.  Add the tool service or remove it from the agent.

`required tool executable does not exist`
: External tools need an executable at `tools/<id>`.  The configured `edit`
  tool also needs an executable `tools/edit` bridge, normally copied from
  `init/tools/edit`.

`required tool manifest does not exist`
: External tools need `tools/<id>.json`.  The built-in `bash` and `edit` tools
  do not require manifests.

`tool must be executable`
: Mark the tool script executable, for example `chmod +x tools/fmt`.

`edit is disabled`, `bash is disabled`, or `edit call denied by operator`
: Check `<tool>_ENABLED` in `tools.conf`.  `YES` allows the tool, `MANUAL`
  prompts before each use, and `NO` disables it.

Startup warning that `sid will run bash and external tools UNSANDBOXED`
: `/usr/bin/sandbox-exec` is unavailable, so `sid` cannot apply the macOS
  Seatbelt wrapper.  Bash and external tools still run, but without that
  sandbox policy.

`sandbox-exec: sandbox_apply: Operation not permitted`
: `sandbox-exec` exists, but the current host or parent sandbox refused to
  apply the policy.  Run `sid` outside the enclosing sandbox or on a macOS
  environment that permits Seatbelt policy application.

## EXIT STATUS

`0`
: Successful interactive session, accepted manual abort, or successful
  `--bash-debug` command.

`1`
: Help display, startup failure, configuration failure, client initialization
  failure, I/O failure, or `--bash-debug` failure.

`64`
: Command-line parse failure reported by `arrrg`.

## EXAMPLES

Start with the bundled manual-confirmation tools:

```sh
SID_HOME=init sid
```

Run a one-shot bash configuration check:

```sh
SID_HOME=init sid --bash-debug 'pwd && ls'
```

Define a formatter tool:

```sh
cat >tools.conf <<'EOF'
fmt_ENABLED="YES"
format_INHERIT="YES"
format_ALIASES="fmt"
EOF

mkdir -p tools agents
```

Expose it to an agent:

```sh
cat >agents.conf <<'EOF'
DEFAULT_AGENT="build"
build_ENABLED="YES"
build_TOOLS="format"
EOF

cat >agents/build.md <<'EOF'
# Build

You are an expert builder.
EOF
```

Implement `tools/fmt`, mark it executable, and place the schema in
`tools/fmt.json`.  Calls to `format` will execute the canonical `fmt` tool while
preserving `format` as the model-visible tool name.

## SEE ALSO

[SID-EDITOR-TOOL(1)](#sid-editor-tool1),
[SID-SEATBELT(1)](#sid-seatbelt1),
[RCINVOKE(1)](#rcinvoke1),
[SANDBOX-EXEC(1)](#sandbox-exec1)

# SID-EDITOR-TOOL(1)

## NAME

sid-editor-tool - execute the sid text-editor tool protocol

## SYNOPSIS

```text
sid-editor-tool
sid-editor-tool --readonly
tools/edit confirm
tools/edit run
tools/read confirm
tools/read run
```

## DESCRIPTION

`sid-editor-tool` is the helper used by the configured `edit` and `read`
tools.  It is not an interactive editor.  In its default mode, `confirm`
simulates mutating editor operations in memory and prints a diff preview to
standard output, while `run` reads a sid tool request from `REQUEST_FILE`,
executes one filesystem edit operation relative to `WORKSPACE_ROOT`, and
writes a sid tool result to `RESULT_FILE`.  With `--readonly`, the helper
serves the `read` tool: it previews read requests, formats file contents with
line numbers, lists directories, and rejects mutating editor commands.  The
helper process is not chrooted, but editor paths are workspace-rooted by the
protocol implementation.

The starter `init/tools/edit` and `init/tools/read` scripts are the normal
entrypoints.  They receive prefixed rc-conf variables from `sid`, export the
unprefixed environment used by `sid-editor-tool`, then exec `sid-editor-tool`
with the appropriate mode flags.

## COMMANDS

`view`
: Read a file.  Input fields are `path` and optional `view_range`.

`str_replace`
: Replace one exact string in a file.  Input fields are `path`, `old_str`, and
  optional `new_str`.

`insert`
: Insert text at a line.  Input fields are `path`, `insert_line`, and either
  `insert_text` or `new_str`.

`create`
: Create a new file.  Input fields are `path` and `file_text`.

## COMMAND INPUT EXAMPLES

These examples show the `invocation.input` object inside the sid tool request
envelope.  The helper normally receives that envelope through `REQUEST_FILE`
when `tools/edit run` is invoked by `sid`.

View a file:

```json
{
  "command": "view",
  "path": "src/lib.rs"
}
```

View a line range:

```json
{
  "command": "view",
  "path": "src/lib.rs",
  "view_range": [10, 40]
}
```

Replace one exact string:

```json
{
  "command": "str_replace",
  "path": "README.md",
  "old_str": "old text",
  "new_str": "new text"
}
```

Insert text at a line:

```json
{
  "command": "insert",
  "path": "README.md",
  "insert_line": 12,
  "insert_text": "Inserted text\n"
}
```

Create a file:

```json
{
  "command": "create",
  "path": "notes/todo.md",
  "file_text": "# Todo\n"
}
```

## ENVIRONMENT

`REQUEST_FILE`
: Path to the JSON request envelope.

`RESULT_FILE`
: Path where the JSON result envelope must be written.

`WORKSPACE_ROOT`
: Workspace root used for filesystem operations.  Leading slashes in editor
  paths are stripped before joining with this directory, so editor path `/`
  names `WORKSPACE_ROOT`, not host `/`.

`DIFF`
: Optional shell command used by `confirm` mode to render mutating edit
  previews from raw unified diff text.  An empty value disables styling and
  prints the raw unified diff.  When unset, the built-in `sidiff` renderer is
  used.

`NO_COLOR`
: Disables ANSI color in the built-in `sidiff` renderer used by `confirm` mode.

## EXIT STATUS

`0`
: The helper read the request and wrote a protocol result.  The result may
  still contain `"ok": false` for handled editor failures.

`nonzero`
: The helper failed before it could complete protocol transport, usually
  because a required environment variable was missing or a request/result file
  could not be read or written.

## SEE ALSO

[SID(1)](#sid1), [SID TOOL PROTOCOL](#tool-protocol)

# SID-SEATBELT(1)

## NAME

sid-seatbelt - run a command inside sid's macOS Seatbelt sandbox policy

## SYNOPSIS

```text
sid-seatbelt [--writable-roots DIR[:DIR...]] -- COMMAND [ARG...]
```

Generated help spells long options with one leading dash.  The parser also
accepts the double-dash form used above.

## DESCRIPTION

`sid-seatbelt` execs `COMMAND` under `/usr/bin/sandbox-exec` using the same
policy builder that `sid` uses for sandboxed bash and external tool processes.
It is a macOS helper; it exits with an error when `/usr/bin/sandbox-exec` is not
available.  It does not chroot `COMMAND`; host `/` remains the process root.

The policy is deny-by-default, permits reads from writable roots outside
`$HOME`, permits writes to configured writable roots and temporary directories,
and limits network access to loopback.  Reads from the user's home directory
are limited to `~/src`, `~/.cargo`, `~/.rustup`, `~/.config/git`, and selected
Git dotfiles such as `~/.gitconfig`.  It also allows
`/Library/Developer/CommandLineTools` for system toolchain support.

## OPTIONS

`--writable-roots DIR[:DIR...]`
: Colon-separated list of directories that should be writable inside the
  sandbox.

## EXAMPLES

Run tests with the current workspace and `/tmp` writable:

```sh
sid-seatbelt --writable-roots "$PWD:/tmp" -- cargo test
```

Start a local development server that may bind a loopback port:

```sh
sid-seatbelt --writable-roots "$PWD:/tmp" -- npm run dev
```

## EXIT STATUS

`1`
: No command was supplied, `sandbox-exec` is unavailable, or exec failed.

Otherwise, `sid-seatbelt` replaces itself with `sandbox-exec`; the final status
is the status reported by the sandboxed command.

## SEE ALSO

[SID(1)](#sid1), [SANDBOX-EXEC(1)](#sandbox-exec1)

# RCINVOKE(1)

## NAME

rcinvoke - invoke rc-style services by reading their advertised variables

## DESCRIPTION

`rcinvoke` is not implemented by this repository, but sid tools are shaped to be
compatible with it.  A sid tool executable answers `rcvar` with the variables it
needs, and answers `run` by performing the tool operation.

During a sid tool call, `RC_CONF_PATH` points at the workspace `tools.conf` plus
sid's per-call overlay, and `RC_D_PATH` points at the configured `tools/`
directory.  A tool can use those values to invoke another configured tool
without reconstructing sid's environment by hand.

## EXAMPLES

Invoke another configured tool from inside a sid tool:

```sh
rcinvoke --rc-conf-path "$RC_CONF_PATH" --rc-d-path "$RC_D_PATH" format
```

## SEE ALSO

[SID(1)](#sid1), [SID TOOL PROTOCOL](#tool-protocol)

# SANDBOX-EXEC(1)

## NAME

sandbox-exec - run a process under a macOS sandbox profile

## DESCRIPTION

`sandbox-exec` is the macOS program sid uses when it is available.  `sid` builds
an SBPL policy at runtime and passes it to `/usr/bin/sandbox-exec` for bash,
external tools, and `sid-seatbelt`.  The policy restricts operations; it does
not replace `/` with the workspace.

When `sandbox-exec` is unavailable, `sid` runs child processes without the
Seatbelt wrapper.  `sid-seatbelt` is stricter: it is specifically a
`sandbox-exec` frontend and exits with an error if the program is missing.

## POLICY

The generated sid policy:

- denies by default;
- allows child process execution and same-sandbox signaling;
- allows reads from writable roots outside `$HOME`, plus `~/src`, `~/.cargo`,
  `~/.rustup`, `~/.config/git`, selected Git dotfiles such as `~/.gitconfig`,
  and `/Library/Developer/CommandLineTools`;
- allows writes to the workspace, configured writable roots, and temporary
  directories;
- allows loopback networking for local servers and tools;
- includes platform allowances needed for common shells, build tools, language
  runtimes, and system libraries.

## SEE ALSO

[SID(1)](#sid1), [SID-SEATBELT(1)](#sid-seatbelt1)