company-skill 4.5.0 → 4.5.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -27,17 +27,17 @@ Optionally define your team first in `COMPANY.md` (skip it and a minimal company
27
27
  ```mermaid
28
28
  graph LR
29
29
  G[GOAL] --> T[THINK]
30
- T -->|contract shape gate| E[EXECUTE]
30
+ T -->|contract shape gate| E[EXECUTE in dependency waves]
31
31
  E -->|findings shape gate| V[VERIFY]
32
32
  V -->|reviewer re-derives + critic attacks| D{Done?}
33
33
  D -->|NO: feedback| C[COMPRESS]
34
34
  C --> T
35
- D -->|YES| S[STATUS.md]
36
- D -.->|stop attempt while failing| B[stop guard blocks]
35
+ D -->|YES| S[STATUS.md + playbook]
36
+ D -.->|stop blocked with the goal and failing notes| B[stop guard]
37
37
  B -.-> T
38
38
  ```
39
39
 
40
- It runs any model the way frontier models like Claude Fable 5 run themselves: delegation contracts, verify layers, and failing-by-default criteria ship as structural artifacts, so the discipline holds whichever model fills each role. The orchestrator reads the goal and activates only the relevant employees. Leads decompose the goal into delegation contracts, workers execute them in parallel waves, and two reviewers gate every cycle: the Internal Reviewer re-runs the evidence and the Devil's Advocate attacks it. There is no iteration limit. The harness carries the quality, so none of it depends on the model remembering to be careful.
40
+ It runs any model with the operating rigor the frontier pair Claude Fable 5 and Mythos demonstrate: delegation contracts, two-pass evidence verification, and failing-by-default criteria ship as structural artifacts, so the discipline holds whichever model fills each role. The orchestrator reads the goal and activates only the relevant employees. Leads decompose the goal into delegation contracts, workers execute them in parallel waves, and two reviewers gate every cycle: the Internal Reviewer re-runs the evidence and the Devil's Advocate attacks it. There is no iteration limit. The harness carries the quality, so none of it depends on the model remembering to be careful.
41
41
 
42
42
  ## Delegation contracts
43
43
 
@@ -33,6 +33,8 @@ Rate each finding's importance 1-5 (the digest keeps 4-5 in full).
33
33
 
34
34
  Report SHORT. Result first, then the evidence (FINDING + SOURCE: the command and its output, the file, the PR/SHA/CI link). No narration of your steps, no restating the task. Concise never means unsourced: cut the prose around a claim, never the source that proves it.
35
35
 
36
+ Narrate intent before consequential tool calls: one short line on what you are about to do and why. A silent agent is far harder for the verify layers to audit, and the audit trail is the product.
37
+
36
38
  Anything a human reads outside the run (a PR body, a comment, an email, a post) gets a /humanizer pass before you publish it: short, professional, human-sounding. Evidence lines stay verbatim. If the skill is missing, self-edit to the same bar and note SKILL-MISSING.
37
39
 
38
40
  End every findings append with one machine-greppable line: `STATUS: complete` when DONE-WHEN is met and verified, `STATUS: blocked` with the blocker named above it, or `STATUS: incomplete` with what remains. The orchestrator greps this line instead of parsing your prose.
package/bin/install.js CHANGED
@@ -16,22 +16,18 @@ function copyFile(src, dest) {
16
16
  fs.copyFileSync(src, dest);
17
17
  }
18
18
 
19
- // Install skill
20
19
  copyFile(path.join(srcDir, 'skill', 'SKILL.md'), path.join(skillDir, 'SKILL.md'));
21
20
 
22
- // Install commands
23
21
  for (const cmd of ['run', 'status', 'resume']) {
24
22
  const src = path.join(srcDir, 'commands', `${cmd}.md`);
25
23
  if (fs.existsSync(src)) copyFile(src, path.join(commandsDir, `${cmd}.md`));
26
24
  }
27
25
 
28
- // Install agents
29
26
  for (const agent of ['lead', 'worker', 'reviewer', 'critic', 'digest']) {
30
27
  const src = path.join(srcDir, 'agents', `company-${agent}.md`);
31
28
  if (fs.existsSync(src)) copyFile(src, path.join(agentsDir, `company-${agent}.md`));
32
29
  }
33
30
 
34
- // Install all hooks
35
31
  const hookFiles = {
36
32
  'stop-guard.js': 'company-stop-guard.js',
37
33
  'precompact.js': 'company-precompact.js',
@@ -52,19 +48,16 @@ try {
52
48
 
53
49
  if (!settings.hooks) settings.hooks = {};
54
50
 
55
- // Stop hook
56
51
  if (!settings.hooks.Stop) settings.hooks.Stop = [];
57
52
  if (!settings.hooks.Stop.some(h => h.hooks?.some(hh => hh.command?.includes('company-stop-guard')))) {
58
53
  settings.hooks.Stop.push({ hooks: [{ type: 'command', command: `node "${path.join(hooksDir, 'company-stop-guard.js')}"`, timeout: 10 }] });
59
54
  }
60
55
 
61
- // PreCompact hook
62
56
  if (!settings.hooks.PreCompact) settings.hooks.PreCompact = [];
63
57
  if (!settings.hooks.PreCompact.some(h => h.hooks?.some(hh => hh.command?.includes('company-precompact')))) {
64
58
  settings.hooks.PreCompact.push({ hooks: [{ type: 'command', command: `node "${path.join(hooksDir, 'company-precompact.js')}"`, timeout: 10 }] });
65
59
  }
66
60
 
67
- // SessionStart hook (compact restore)
68
61
  if (!settings.hooks.SessionStart) settings.hooks.SessionStart = [];
69
62
  if (!settings.hooks.SessionStart.some(h => h.hooks?.some(hh => hh.command?.includes('company-session-restore')))) {
70
63
  settings.hooks.SessionStart.push({ matcher: 'compact', hooks: [{ type: 'command', command: `node "${path.join(hooksDir, 'company-session-restore.js')}"`, timeout: 10 }] });
@@ -79,7 +72,6 @@ try {
79
72
  console.log('Could not register hooks. Add manually to settings.json.');
80
73
  }
81
74
 
82
- // Create COMPANY.md template
83
75
  const companyMd = path.join(process.cwd(), 'COMPANY.md');
84
76
  const template = path.join(srcDir, 'COMPANY.md.template');
85
77
  if (!fs.existsSync(companyMd) && fs.existsSync(template)) {
@@ -87,7 +79,6 @@ if (!fs.existsSync(companyMd) && fs.existsSync(template)) {
87
79
  console.log('Created COMPANY.md template.');
88
80
  }
89
81
 
90
- // Gitignore
91
82
  try {
92
83
  const gi = path.join(process.cwd(), '.gitignore');
93
84
  const content = fs.existsSync(gi) ? fs.readFileSync(gi, 'utf8') : '';
@@ -1,7 +1,8 @@
1
1
  #!/usr/bin/env node
2
2
 
3
- // Save company state AND reasoning before context compaction.
4
- // Saves both numbers (criteria, cycle) and intent (what we're trying and why).
3
+ // Saves company state before context compaction so session-restore can rebuild
4
+ // the model's context. Snapshots goal, cycle, briefing, review, criteria, roster,
5
+ // and the TAIL of the playbook (new entries append at the bottom).
5
6
 
6
7
  const fs = require('fs');
7
8
  const path = require('path');
@@ -9,9 +10,9 @@ const path = require('path');
9
10
  const companyDir = process.env.COMPANY_DIR || path.join(process.cwd(), '.company');
10
11
  if (!fs.existsSync(companyDir)) process.exit(0);
11
12
 
12
- // Only sessions that own the run are acted on. A foreign session that merely
13
- // shares the directory must not be redirected or have state written on its
14
- // behalf. Missing or empty OWNER is legacy state and keeps the old behavior.
13
+ // Only sessions listed in OWNER are acted on. A foreign session that shares the
14
+ // directory must not have state written on its behalf. Missing or empty OWNER
15
+ // keeps the old behavior (act on all sessions).
15
16
  try {
16
17
  const hookInput = JSON.parse(fs.readFileSync(0, 'utf8'));
17
18
  if (hookInput && typeof hookInput.session_id === 'string') {
@@ -23,7 +24,6 @@ try {
23
24
 
24
25
  const lines = ['# Company Checkpoint (auto-saved before compaction)', ''];
25
26
 
26
- // Goal
27
27
  const goalPath = path.join(companyDir, 'GOAL.md');
28
28
  if (fs.existsSync(goalPath)) {
29
29
  lines.push('## Goal');
@@ -31,7 +31,6 @@ if (fs.existsSync(goalPath)) {
31
31
  lines.push('');
32
32
  }
33
33
 
34
- // Cycle number
35
34
  const cyclesDir = path.join(companyDir, 'cycles');
36
35
  if (fs.existsSync(cyclesDir)) {
37
36
  const files = fs.readdirSync(cyclesDir).filter(f => f.startsWith('cycle-'));
@@ -40,7 +39,6 @@ if (fs.existsSync(cyclesDir)) {
40
39
  lines.push('## Cycle: ' + cycle);
41
40
  lines.push('');
42
41
 
43
- // Latest briefing (captures current reasoning/intent)
44
42
  const briefing = path.join(cyclesDir, `cycle-${cycle}-briefing.md`);
45
43
  if (fs.existsSync(briefing)) {
46
44
  lines.push('## Current Reasoning');
@@ -48,7 +46,6 @@ if (fs.existsSync(cyclesDir)) {
48
46
  lines.push('');
49
47
  }
50
48
 
51
- // Latest review (captures what's working/failing)
52
49
  const review = path.join(cyclesDir, `cycle-${cycle}-review.md`);
53
50
  if (fs.existsSync(review)) {
54
51
  lines.push('## Latest Review');
@@ -57,7 +54,6 @@ if (fs.existsSync(cyclesDir)) {
57
54
  }
58
55
  }
59
56
 
60
- // Criteria status
61
57
  const criteriaPath = path.join(companyDir, 'criteria.json');
62
58
  if (fs.existsSync(criteriaPath)) {
63
59
  try {
@@ -71,7 +67,6 @@ if (fs.existsSync(criteriaPath)) {
71
67
  } catch (e) {}
72
68
  }
73
69
 
74
- // Active roster
75
70
  const rosterPath = path.join(companyDir, 'active-roster.md');
76
71
  if (fs.existsSync(rosterPath)) {
77
72
  lines.push('## Active Roster');
@@ -79,8 +74,7 @@ if (fs.existsSync(rosterPath)) {
79
74
  lines.push('');
80
75
  }
81
76
 
82
- // Playbook (accumulated lessons). New session entries are appended at the
83
- // bottom, so snapshot the TAIL, not the head.
77
+ // New playbook entries append at the bottom, so snapshot the tail, not the head.
84
78
  const playbookPath = path.join(companyDir, 'playbook.md');
85
79
  if (fs.existsSync(playbookPath)) {
86
80
  const playbook = fs.readFileSync(playbookPath, 'utf8');
@@ -1,14 +1,10 @@
1
1
  #!/usr/bin/env node
2
2
 
3
- // Restore company state after compaction and drive the /company restart handoff.
4
- // PreCompact cannot make the model emit a prompt (shell-only, no model turn before
5
- // compaction), so the reliable trigger is here: right after compaction the model is
6
- // instructed to run /company restart (its mandatory verify and debate procedure)
7
- // and emit the handoff.
8
- //
9
- // SessionStart context must go through hookSpecificOutput.additionalContext.
10
- // That field reaches the model. systemMessage is a user-facing display only and
11
- // never enters the model's context.
3
+ // Restores company context after compaction and instructs the model to run the
4
+ // /company restart procedure before continuing.
5
+ // Context must go through hookSpecificOutput.additionalContext - that field
6
+ // reaches the model. systemMessage is user-facing display only and never enters
7
+ // the model's context.
12
8
 
13
9
  const fs = require('fs');
14
10
  const path = require('path');
@@ -16,9 +12,8 @@ const path = require('path');
16
12
  const companyDir = process.env.COMPANY_DIR || path.join(process.cwd(), '.company');
17
13
  if (!fs.existsSync(companyDir)) process.exit(0);
18
14
 
19
- // Only sessions that own the run are acted on. A foreign session that merely
20
- // shares the directory must not be redirected or have state written on its
21
- // behalf. Missing or empty OWNER is legacy state and keeps the old behavior.
15
+ // Only sessions listed in OWNER are acted on. A foreign session that shares the
16
+ // directory must not be redirected. Missing or empty OWNER keeps the old behavior.
22
17
  try {
23
18
  const hookInput = JSON.parse(fs.readFileSync(0, 'utf8'));
24
19
  if (hookInput && typeof hookInput.session_id === 'string') {
@@ -34,7 +29,6 @@ if (fs.existsSync(checkpointMd)) {
34
29
  state = fs.readFileSync(checkpointMd, 'utf8').substring(0, 2000);
35
30
  }
36
31
 
37
- // The post-compaction directive: run the restart procedure, do not just "continue".
38
32
  const directive =
39
33
  '[COMPANY] Context was compacted, so prior turn-by-turn state is gone. Before doing ' +
40
34
  'anything else, run the /company restart procedure from the skill: refresh ' +
package/install.sh CHANGED
@@ -1,6 +1,6 @@
1
1
  #!/bin/bash
2
- # Installs the /company skill, commands, agents, AND hooks. Idempotent:
3
- # re-running overwrites the copied files and never duplicates hook entries.
2
+ # Installs the /company skill, commands, agents, and hooks.
3
+ # Idempotent: re-running overwrites copied files and never duplicates hook entries.
4
4
  set -e
5
5
 
6
6
  REPO="https://raw.githubusercontent.com/jagmarques/company-skill/main"
@@ -33,7 +33,7 @@ for agent in lead worker reviewer critic digest; do
33
33
  fetch "$REPO/agents/company-$agent.md" "$HOME/.claude/agents/company-$agent.md" || echo "Warning: failed to download agent company-$agent"
34
34
  done
35
35
 
36
- # Hooks (the stop gate and the compaction machinery live here)
36
+ # Hooks
37
37
  mkdir -p "$HOME/.claude/hooks"
38
38
  for pair in "stop-guard company-stop-guard" "precompact company-precompact" "session-restore company-session-restore"; do
39
39
  src="${pair%% *}"
@@ -41,9 +41,8 @@ for pair in "stop-guard company-stop-guard" "precompact company-precompact" "ses
41
41
  fetch "$REPO/hooks/$src.js" "$HOME/.claude/hooks/$dest.js" || echo "Warning: failed to download hook $src"
42
42
  done
43
43
 
44
- # Register hooks in ~/.claude/settings.json. JSON editing from shell is not
45
- # safe without a JSON tool, so use node when available and print exact manual
46
- # steps otherwise. The merge is idempotent: existing entries are kept.
44
+ # JSON editing from shell is unsafe without a JSON tool. Use node when available
45
+ # and print exact manual steps otherwise. The merge is idempotent.
47
46
  if command -v node >/dev/null 2>&1; then
48
47
  node <<'EOF'
49
48
  const fs = require('fs');
package/package.json CHANGED
@@ -1,11 +1,11 @@
1
1
  {
2
2
  "name": "company-skill",
3
- "version": "4.5.0",
3
+ "version": "4.5.1",
4
4
  "description": "Goal-driven multi-employee company for Claude Code. Give it a goal, it runs until done.",
5
5
  "bin": {
6
6
  "company-skill": "./bin/install.js"
7
7
  },
8
- "keywords": ["claude-code", "skill", "multi-agent", "company", "orchestration", "model-agnostic", "autonomous-agents", "stop-hook", "agent-orchestration", "ai-agents", "fable", "claude-fable"],
8
+ "keywords": ["claude-code", "skill", "multi-agent", "company", "orchestration", "model-agnostic", "autonomous-agents", "stop-hook", "agent-orchestration", "ai-agents", "fable", "claude-fable", "mythos", "claude-mythos"],
9
9
  "author": "jagmarques",
10
10
  "license": "MIT",
11
11
  "repository": {
@@ -1,8 +1,7 @@
1
1
  #!/usr/bin/env node
2
- // Mechanical gate for delegation contracts: every TASK block must carry all
3
- // seven fields and a non-empty VERIFY-WITH. Run before EXECUTE:
4
- // node scripts/check-contracts.js .company/cycles/cycle-N-tasks.md
5
- // Exit 1 lists each defective contract. No fields, no task.
2
+ // Gate for delegation contracts: every TASK block must carry all seven fields
3
+ // and a non-empty VERIFY-WITH. Exit 1 lists each defective contract.
4
+ // Run: node scripts/check-contracts.js .company/cycles/cycle-N-tasks.md
6
5
  const fs = require('fs');
7
6
  const file = process.argv[2];
8
7
  if (!file || !fs.existsSync(file)) { console.error('usage: check-contracts.js <tasks-file>'); process.exit(2); }
@@ -10,8 +9,8 @@ const text = fs.readFileSync(file, 'utf8');
10
9
  const blocks = text.split(/\n(?=TASK:)/).filter(b => b.trim().startsWith('TASK:'));
11
10
  if (blocks.length === 0) { console.error('no TASK blocks found'); process.exit(1); }
12
11
  const FIELDS = ['TASK:', 'EMPLOYEE:', 'SKILL:', 'INPUTS:', 'OUTPUT:', 'DONE-WHEN:', 'VERIFY-WITH:', 'OUT-OF-SCOPE:'];
13
- // DEPENDS-ON is optional. When present it must name existing task numbers
14
- // and the dependency graph must be acyclic.
12
+ // DEPENDS-ON is optional. When present it must name existing task numbers and the
13
+ // dependency graph must be acyclic.
15
14
  function checkDeps(blocks) {
16
15
  const errs = [];
17
16
  const deps = blocks.map((b, i) => {
@@ -1,8 +1,7 @@
1
1
  #!/usr/bin/env node
2
- // Mechanical gate for findings files: every FINDING line must be followed by
3
- // a SOURCE line (or NOVEL marker) before the next FINDING. Run at VERIFY:
4
- // node scripts/check-findings.js .company/<dept>/<employee>.md [...]
5
- // Exit 1 names each unsourced finding. A claim without a source is unverifiable.
2
+ // Gate for findings files: every FINDING line must be followed by a SOURCE
3
+ // line (or NOVEL marker) before the next FINDING. A claim without a source
4
+ // is unverifiable. Run: node scripts/check-findings.js .company/<dept>/<employee>.md [...]
6
5
  const fs = require('fs');
7
6
  const files = process.argv.slice(2);
8
7
  if (!files.length) { console.error('usage: check-findings.js <findings-file...>'); process.exit(2); }
@@ -1,11 +1,9 @@
1
1
  #!/usr/bin/env node
2
2
 
3
- // Decision-logic matrix for hooks/stop-guard.js. Each case builds a fixture
4
- // state dir, runs the hook with COMPANY_DIR pointed at it, and asserts the
5
- // allow/block decision from the hook's stdout contract: a block prints a
6
- // JSON object with decision "block", an allow prints nothing and exits 0.
7
- // The CI floor (scripts/check.sh) runs this file, so a future edit cannot
8
- // regress the fail-closed behavior with CI still green.
3
+ // Decision-logic matrix for hooks/stop-guard.js. Builds a fixture dir per case,
4
+ // runs the hook with COMPANY_DIR pointed at it, and asserts allow/block from
5
+ // stdout. A block emits JSON with decision "block"; allow exits 0 with no output.
6
+ // Included in scripts/check.sh so a future edit cannot silently regress fail-closed.
9
7
 
10
8
  const { execFileSync } = require('child_process');
11
9
  const fs = require('fs');
@@ -65,13 +63,13 @@ function writeCriteria(dir, value) {
65
63
  typeof value === 'string' ? value : JSON.stringify(value));
66
64
  }
67
65
 
68
- // 1. No company state at all: the hook must stay silent (allow).
66
+ // 1. No company state: hook must allow silently.
69
67
  {
70
68
  const d = freshDir();
71
69
  check('no state allows', d, 'allow');
72
70
  }
73
71
 
74
- // 2. CANCEL file: allows the stop AND is consumed so it cannot leak into a later run.
72
+ // 2. CANCEL file allows and must be consumed so it cannot leak into a later run.
75
73
  {
76
74
  const d = freshDir();
77
75
  fs.writeFileSync(path.join(d, 'GOAL.md'), 'goal');
@@ -114,14 +112,14 @@ function writeCriteria(dir, value) {
114
112
  check('failing criterion blocks', d, 'block', 'ship it');
115
113
  }
116
114
 
117
- // 7. passes true with null evidence still blocks: evidence is the contract.
115
+ // 7. passes:true without evidence still blocks; evidence is the contract.
118
116
  {
119
117
  const d = freshDir();
120
118
  writeCriteria(d, { criteria: [{ id: 1, description: 'ev gap', passes: true, evidence: null }] });
121
119
  check('passes without evidence blocks', d, 'block', 'ev gap');
122
120
  }
123
121
 
124
- // 8. All passing with evidence allows the stop.
122
+ // 8. All criteria passing with evidence allows the stop.
125
123
  {
126
124
  const d = freshDir();
127
125
  writeCriteria(d, { criteria: [
@@ -154,7 +152,7 @@ function writeCriteria(dir, value) {
154
152
  check('stale still blocks with age note', d, 'block', 'untouched for');
155
153
  }
156
154
 
157
- // 12. Session scoping: a foreign session passes when OWNER names another session.
155
+ // 12. A foreign session passes when OWNER names a different session.
158
156
  {
159
157
  const d = freshDir();
160
158
  writeCriteria(d, { criteria: [{ id: 1, description: 'a', passes: false, evidence: null }] });
@@ -201,7 +199,7 @@ function writeCriteria(dir, value) {
201
199
  { input: JSON.stringify({ session_id: 'owner-eee' }) });
202
200
  }
203
201
 
204
- // 17. Deleting a locked criterion blocks even when everything left passes.
202
+ // 17. Deleting a locked criterion blocks even when everything remaining passes.
205
203
  {
206
204
  const d = freshDir();
207
205
  writeCriteria(d, { criteria: [
@@ -213,7 +211,7 @@ function writeCriteria(dir, value) {
213
211
  check('deleting a locked criterion blocks', d, 'block', 'locked criterion');
214
212
  }
215
213
 
216
- // 18. Adding a criterion extends the lock and a fully passing set allows.
214
+ // 18. Adding a criterion extends the lock; a fully passing set allows.
217
215
  {
218
216
  const d = freshDir();
219
217
  writeCriteria(d, { criteria: [
@@ -233,7 +231,7 @@ function writeCriteria(dir, value) {
233
231
  }
234
232
  }
235
233
 
236
- // 19. No block reason ever hands the model the cancel command.
234
+ // 19. The block reason must not reveal the cancel command to the model.
237
235
  {
238
236
  const d = freshDir();
239
237
  writeCriteria(d, { criteria: [{ id: 1, description: 'a', passes: false, evidence: null }] });