Skip to content

13 · install-empty-dir

What this scenario proves

archon install succeeds on a fully empty directory — no package.json, no pyproject.toml, no source files, nothing but a single placeholder README. This is the null reference point for the install-matrix: the simplest "before" state imaginable, and the upper bound on what install can possibly add.

A passing run here proves three things:

  1. Install does not require any pre-existing language manifest (package.json / pyproject.toml / go.mod / Cargo.toml).
  2. Install does not require any business code or runnable tests.
  3. Seeded runtime ledgers (.archon/drift.md, .archon/manifest.md, etc.) are created from seedRuntimeLedgers() even when the target tree is otherwise empty.

This scenario pairs with 14 · install-existing-project to bracket the install behaviour: 13 is "install adds everything", 14 is "install adds Archon files and touches nothing else".

Test environment

Fixturefixtures/sandbox-empty
IDECursor (default; binding directory .cursor/ is laid out)
OSmacOS 14 / Ubuntu 22.04 / Windows 11
Archon sourcelocal mirror of docs/public/manifest.json (sandbox runner)
Manifest version under testv0.1.x
Language toolchainnone

Pre-conditions

  1. Fixture copied to a fresh tmp dir (the runner does this automatically).
  2. No .archon/ and no .cursor/ exist.

Steps

text
1. Run:
     archon install --with=cli
2. Wait for the "install complete" summary line.

Expected outcome

CheckExpected
Exit code (CLI)0
.archon/VERSIONexists, matches manifest version
.archon/soul.mdexists
.archon/manifest.mdexists (seeded header)
.archon/drift.mdexists; contains exactly one ## install row
.cursor/commands/archon.mdexists
.cursor/rules/exists
.cursor/skills/exists
tools/archon-cli/ (because --with=cli)exists
.archon-backup-* (no force, no prior install)absent

Demo recordings

Will be replaced by docs/public/videos/install-empty-dir.mp4 once recorded. See videos/README for upload conventions.
Will be replaced by docs/public/asciinema/install-empty-dir.cast embedded via the asciinema-player web component. See asciinema/README for the recording command.

Run records

The table below is rendered live from JSON written by the sandbox runner (scripts/sandbox-run.mjs) under docs/testing/sandbox/runs/install-empty-dir/. To add a new row, run

bash
node scripts/sandbox-run.mjs --only=install-empty-dir
Started (UTC)ManifestRunnerResultDurationNotesRecord
2026-06-08 08:17:10 UTCv0.1.0cli✅ passing310 msJSON
2026-06-07 07:10:15 UTCv0.1.0cli✅ passing328 msJSON
2026-06-06 06:34:39 UTCv0.1.0cli✅ passing329 msJSON
2026-06-05 07:14:06 UTCv0.1.0cli✅ passing308 msJSON
2026-06-04 07:56:42 UTCv0.1.0cli✅ passing381 msJSON
2026-06-03 08:24:16 UTCv0.1.0cli✅ passing369 msJSON
2026-06-02 08:00:50 UTCv0.1.0cli✅ passing321 msJSON
2026-06-01 08:40:44 UTCv0.1.0cli✅ passing337 msJSON
2026-05-31 07:02:23 UTCv0.1.0cli✅ passing336 msJSON
2026-05-30 06:27:52 UTCv0.1.0cli✅ passing315 msJSON
2026-05-29 06:59:38 UTCv0.1.0cli✅ passing373 msJSON
2026-05-28 06:59:32 UTCv0.1.0cli✅ passing345 msJSON
2026-05-27 07:09:41 UTCv0.1.0cli✅ passing350 msJSON
2026-05-26 06:52:08 UTCv0.1.0cli✅ passing282 msJSON
2026-05-25 07:20:21 UTCv0.1.0cli✅ passing320 msJSON
2026-05-24 06:41:51 UTCv0.1.0cli✅ passing333 msJSON
2026-05-23 06:16:49 UTCv0.1.0cli✅ passing334 msJSON
2026-05-22 06:54:17 UTCv0.1.0cli✅ passing335 msJSON
2026-05-21 06:58:03 UTCv0.1.0cli✅ passing314 msJSON
2026-05-20 06:53:36 UTCv0.1.0cli✅ passing314 msJSON
2026-05-19 06:53:17 UTCv0.1.0cli✅ passing311 msJSON
2026-05-18 07:01:46 UTCv0.1.0cli✅ passing336 msJSON
2026-05-17 06:27:35 UTCv0.1.0cli✅ passing325 msJSON
2026-05-16 06:04:39 UTCv0.1.0cli✅ passing308 msJSON
2026-05-15 06:37:58 UTCv0.1.0cli✅ passing351 msJSON
2026-05-14 06:28:55 UTCv0.1.0cli✅ passing332 msJSON
2026-05-13 06:30:24 UTCv0.1.0cli✅ passing295 msJSON
2026-05-12 06:18:59 UTCv0.1.0cli✅ passing323 msJSON
2026-05-11 06:45:34 UTCv0.1.0cli✅ passing316 msJSON
2026-05-10 06:16:43 UTCv0.1.0cli✅ passing337 msJSON
2026-05-09 05:52:36 UTCv0.1.0cli✅ passing265 msJSON
2026-05-08 05:33:34 UTCv0.1.0cli✅ passing347 msJSON
2026-05-07 11:01:02 UTCv0.1.0cli✅ passing327 msJSON
2026-05-07 09:54:52 UTCv0.1.0cli✅ passing327 msJSON
2026-05-07 09:45:11 UTCv0.1.0cli✅ passing520 msJSON
2026-05-07 06:15:43 UTCv0.1.0cli✅ passing248 msJSON
2026-05-06 11:45:36 UTCv0.1.0cli✅ passing316 msJSON
2026-05-06 11:44:05 UTCv0.1.0cli✅ passing324 msJSON
2026-05-06 11:19:25 UTCv0.1.0cli✅ passing348 msJSON
2026-05-06 11:15:59 UTCv0.1.0cli✅ passing354 msJSON
2026-05-06 11:14:04 UTCv0.1.0cli❌ failing267 msfailed assertions: cmd_zero: ["node","-e","const fs=require('fs');const c=fs.readFileSync('.archon/drift.md','utf8');const m=c.match(/^## install /gm);const n=m?m.length:0;if(n!==1){console.error('expected 1 install row, got',n);process.exit(1)}"]: cmd exited 1: node -e const fs=require('fs');const c=fs.readFileSync('.archon/drift.md','utf8');const m=c.match(/^## install /gm);const n=m?m.length:0;if(n!==1){console.error('expected 1 install row, got',n);process.exit(1)} stderr-tail: m:185:14) at compileScript (node:internal/process/execution:386:10) at node:internal/process/execution:450:25 at [eval]-wrapper:6:24 at runScriptInContext (node:internal/process/execution:447:60) at evalFunction (node:internal/process/execution:87:30) at evalScript (node:internal/process/execution:99:3) at node:internal/main/eval_string:74:3 Node.js v22.14.0 JSON
2026-05-06 11:12:53 UTCv0.1.0cli❌ failing274 msfailed assertions: cmd_zero: ["node","-e","const fs=require('fs');const c=fs.readFileSync('.archon/drift.md','utf8');const n=(c.match(/^## install /gm)||[]).length;if(n!==1){console.error('expected 1 install row, got',n);process.exit(1)}"]: cmd exited 1: node -e const fs=require('fs');const c=fs.readFileSync('.archon/drift.md','utf8');const n=(c.match(/^## install /gm)||[]).length;if(n!==1){console.error('expected 1 install row, got',n);process.exit(1)} stderr-tail: s/execution:450:25 at [eval]-wrapper:6:24 at runScriptInContext (node:internal/process/execution:447:60) at evalFunction (node:internal/process/execution:87:30) at evalScript (node:internal/process/execution:99:3) at node:internal/main/eval_string:74:3 Node.js v22.14.0 '[]).length' is not recognized as an internal or external command, operable program or batch file. JSON

Known limitations

  • Does not test what happens if the directory does not exist at all. install.mjs calls fs.mkdir(targetDir, { recursive: true }) so a non-existent path is handled, but that is exercised by the CLI's own unit tests, not by the sandbox.
  • Does not validate the ledger seeding content (drift body, manifest header) line-by-line — only that the files exist. A future scenario may diff the seeded headers against seedRuntimeLedgers() literals.

Cross-references

json
{
  "runnable": "cli",
  "fixture": "fixtures/sandbox-empty",
  "ide_platform": "cursor",
  "prerequisites": [
    {
      "name": "drop sandbox check helper",
      "write_file": {
        "path": "__sb-check.cjs",
        "content": "const fs=require('fs');const op=process.argv[2];const args=process.argv.slice(3);if(op==='drift-install-count'){const want=Number(args[0]);const c=fs.readFileSync('.archon/drift.md','utf8');const m=c.match(/^## install /gm);const n=m?m.length:0;if(n!==want){console.error('drift install rows: want',want,'got',n);process.exit(1)}process.exit(0)}if(op==='no-backup-dir'){const found=fs.readdirSync('.').some(function(x){return x.indexOf('.archon-backup-')===0});if(found){console.error('unexpected .archon-backup-*');process.exit(1)}process.exit(0)}if(op==='has-backup-dir'){const found=fs.readdirSync('.').some(function(x){return x.indexOf('.archon-backup-')===0});if(!found){console.error('expected .archon-backup-* missing');process.exit(1)}process.exit(0)}if(op==='pkg-name-equals'){const p=require('./package.json');if(p.name!==args[0]){console.error('package.json name mutated:',p.name);process.exit(1)}process.exit(0)}if(op==='file-includes'){const text=fs.readFileSync(args[0],'utf8');if(text.indexOf(args[1])===-1){console.error(args[0],'missing',args[1]);process.exit(1)}process.exit(0)}if(op==='drift-modules-excludes'){const c=fs.readFileSync('.archon/drift.md','utf8');const re=new RegExp('^- Modules:.*\\\\b'+args[0]+'\\\\b','m');if(re.test(c)){console.error(args[0],'unexpectedly listed');process.exit(1)}process.exit(0)}console.error('unknown op:',op);process.exit(2);\n"
      }
    }
  ],
  "steps": [
    {
      "name": "archon install --with=cli",
      "cli": "install",
      "flags": ["--with=cli"]
    }
  ],
  "assertions": [
    { "file_exists": ".archon/VERSION" },
    { "file_exists": ".archon/soul.md" },
    { "file_exists": ".archon/manifest.md" },
    { "file_exists": ".archon/drift.md" },
    { "dir_exists": ".cursor/commands" },
    { "dir_exists": ".cursor/rules" },
    { "dir_exists": ".cursor/skills" },
    { "file_exists": ".cursor/commands/archon.md" },
    { "dir_exists": "tools/archon-cli" },
    { "file_exists": "scripts/archon-check.py" },
    { "cmd_zero": ["node", "__sb-check.cjs", "drift-install-count", "1"] },
    { "cmd_zero": ["node", "__sb-check.cjs", "no-backup-dir"] },
    { "cmd_zero": ["python3", "scripts/archon-check.py", "--root", "."] }
  ],
  "notes": "Null reference point for the install matrix: empty dir + minimal flags. The __sb-check.cjs helper is written by a prerequisite step and provides cross-platform-safe assertions (Windows shell-quoting strips embedded quotes from `node -e ...`)."
}

Released under the Apache-2.0 License.