/60-setup
Use the Bash tool to prepare the workspace (in PROJECT_ROOT):
$ npx -y skills add heurema/signum --agent claude-codeHow it fires
How this command gets triggered: by you, by Claude, or both.
- Fires itselfClaude auto-loads it when your prompt matches the work.
- You can call itInvoke it directly when you want it.
- Slash command
/60-setup
Context preview
What this command does when you run it.
Use the Bash tool to prepare the workspace (in PROJECT_ROOT):
Command definition
60-setup.mdSetup
Use the Bash tool to prepare the workspace (in PROJECT_ROOT):
cd "$PROJECT_ROOT" || exit 1
mkdir -p .signum/contracts
touch .gitignore
grep -q '^\.signum/$' .gitignore || echo '.signum/' >> .gitignore
# Check external CLI availability
CODEX_INSTALLED=$(which codex > /dev/null 2>&1 && echo "yes" || echo "no")
GEMINI_INSTALLED=$(which gemini > /dev/null 2>&1 && echo "yes" || echo "no")
EXTERNAL_COUNT=0
[ "$CODEX_INSTALLED" = "yes" ] && EXTERNAL_COUNT=$((EXTERNAL_COUNT + 1))
[ "$GEMINI_INSTALLED" = "yes" ] && EXTERNAL_COUNT=$((EXTERNAL_COUNT + 1))
echo "External providers: codex=$CODEX_INSTALLED gemini=$GEMINI_INSTALLED ($EXTERNAL_COUNT/2)"
if [ "$EXTERNAL_COUNT" -eq 0 ]; then
echo "NOTE: No external review CLIs installed. Single-model mode:"
echo " - low risk: AUTO_OK possible (Claude review sufficient)"
echo " - medium risk: AUTO_OK possible (graceful degradation)"
echo " - high risk: AUTO_OK requires manual review (multi-model required)"
echo " Install codex/gemini for full multi-model audit."
fi
Model Configuration
Resolve external CLI model overrides from `~/.claude/emporium-providers.local.md`. This file uses YAML frontmatter to configure models for codex and gemini invocations.
Use the Bash tool to define the `_resolve_model` helper and resolve models for this session:
_resolve_model() {
local task="$1" provider="$2"
local config="${EMPORIUM_PROVIDERS_CONFIG:-$HOME/.claude/emporium-providers.local.md}"
[ -f "$config" ] || return 0
python3 -c "
import sys, re, os
config_path = os.environ.get('EMPORIUM_PROVIDERS_CONFIG', os.path.expanduser('~/.claude/emporium-providers.local.md'))
try:
with open(config_path) as f:
text = f.read()
except Exception:
sys.exit(0)
# Extract YAML frontmatter
m = re.match(r'^---\s*\n(.*?)\n---', text, re.DOTALL)
if not m:
sys.exit(0)
fm = m.group(1)
# Minimal YAML parser (stdlib only, no PyYAML dependency)
def parse_yaml_flat(lines):
\"\"\"Parse simple nested YAML into dot-separated key dict.\"\"\"
result = {}
stack = [] # (indent_level, key_prefix)
for line in lines:
stripped = line.rstrip()
if not stripped or stripped.startswith('#'):
continue
indent = len(line) - len(line.lstrip())
# pop stack to find parent
while stack and stack[-1][0] >= indent:
stack.pop()
prefix = stack[-1][1] + '.' if stack else ''
if ':' in stripped:
key, _, val = stripped.partition(':')
key = key.strip()
val = val.strip().strip('\"').strip(\"'\")
full_key = prefix + key
if val:
result[full_key] = val
stack.append((indent, full_key))
return result
data = parse_yaml_flat(fm.split('\n'))
task = '$task'
provider = '$provider'
# Resolution order: routing.task.provider -> routing.default.provider -> defaults.provider.model
model = ''
for lookup in [f'routing.{task}.{provider}', f'routing.default.{provider}', f'defaults.{provider}.model']:
if lookup in data:
model = data[lookup]
break
# Validate model name
if model and not re.match(r'^[A-Za-z0-9._:-]+\$', model):
model = ''
print(model)
" 2>/dev/null
}
SIGNUM_CODEX_MODEL=$(_resolve_model "review" "codex")
SIGNUM_GEMINI_MODEL=$(_resolve_model "review" "gemini")
SIGNUM_CODEX_PROFILE="${SIGNUM_CODEX_PROFILE:-}"
echo "codex_model=${SIGNUM_CODEX_MODEL:-(cli default)} gemini_model=${SIGNUM_GEMINI_MODEL:-(cli default)} codex_profile=${SIGNUM_CODEX_PROFILE:-(none)}"Save `SIGNUM_CODEX_MODEL` and `SIGNUM_GEMINI_MODEL` for use in all subsequent codex/gemini invocations. If either is empty, do NOT pass `--model` — let the CLI use its built-in default.
Use the `PROJECT_ROOT` determined during Project Resolution. Verify we are in the correct directory:
Check for a resumable working set using `contracts/index.json` first. Root `.signum/contract.json` is only a legacy fallback during the migration:
source lib/contract-dir.sh
RESUME_INFO=$(describe_active_contract_state)
RESUME_STATE=$(printf '%s' "$RESUME_INFO" | jq -r '.state')
RESUME_CONTRACT_ID=$(printf '%s' "$RESUME_INFO" | jq -r '.contractId // empty')
RESUME_STATUS=$(printf '%s' "$RESUME_INFO" | jq -r '.status // empty')
if [ "$RESUME_STATE" = "NONE" ] && [ -f .signum/contract.json ] && [ ! -L .signum/contract.json ]; then
if [ -f .signum/execution_context.json ] && [ ! -L .signum/execution_context.json ]; then
RESUME_STATE="LEGACY_RESUMABLE"
else
RESUME_STATE="LEGACY_CONTRACT_ONLY"
fi
fi
jq -n \
--arg state "$RESUME_STATE" \
--arg contractId "$RESUME_CONTRACT_ID" \
--arg status "$RESUME_STATUS" \
'{
state: $state,
contractId: (if $contractId == "" then null else $contractId end),
status: (if $status == "" then null else $status end)
}'- If `.state == "RESUMABLE"`: an active contract exists in `contracts/index.json`. Ask the user: "Active contract `<contractId>` is in progress. Resume from Phase 2, or restart from Phase 1 (discards the active working set)?"
- If `.state == "CONTRACT_ONLY"`: an active contract exists but execution has not started. Ask: "Active contract `<contractId>` exists but execution has not started. Resume from Phase 2, or restart from Phase 1 (new contract)?"
- If `.state == "LEGACY_RESUMABLE"` or `.state == "LEGACY_CONTRACT_ONLY"`: a legacy root-based working set exists outside the contract registry. Ask: "A legacy `.signum/` working set was found. Resume by migrating it into `.signum/contracts/`, or restart from Phase 1?"
- If `.state == "NONE"`: proceed to Phase 1.
If the user chooses to resume a legacy root-based working set, migrate it into the canonical active contract directory before continuing:
source lib/contract-dir.sh
LEGACY_CONTRACT_ID=$(jq -r '.contractId // empty' .signum/contract.json 2>/dev/null || true)
if [ -z "$LEGACY_CONTRACT_ID" ] || [ "$LEGACY_CONTRACT_ID" = "null" ]; then
LEGACY
Read more
Setup
Use the Bash tool to prepare the workspace (in PROJECT_ROOT):
cd "$PROJECT_ROOT" || exit 1 mkdir -p .signum/contracts touch .gitignore grep -q '^\.signum/$' .gitignore || echo '.signum/' >> .gitignore # Check external CLI availability CODEX_INSTALLED=$(which codex > /dev/null 2>&1 && echo "yes" || echo "no") GEMINI_INSTALLED=$(which gemini > /dev/null 2>&1 && echo "yes" || echo "no") EXTERNAL_COUNT=0 [ "$CODEX_INSTALLED" = "yes" ] && EXTERNAL_COUNT=$((EXTERNAL_COUNT + 1)) [ "$GEMINI_INSTALLED" = "yes" ] && EXTERNAL_COUNT=$((EXTERNAL_COUNT + 1)) echo "External providers: codex=$CODEX_INSTALLED gemini=$GEMINI_INSTALLED ($EXTERNAL_COUNT/2)" if [ "$EXTERNAL_COUNT" -eq 0 ]; then echo "NOTE: No external review CLIs installed. Single-model mode:" echo " - low risk: AUTO_OK possible (Claude review sufficient)" echo " - medium risk: AUTO_OK possible (graceful degradation)" echo " - high risk: AUTO_OK requires manual review (multi-model required)" echo " Install codex/gemini for full multi-model audit." fi
Model Configuration
Resolve external CLI model overrides from `~/.claude/emporium-providers.local.md`. This file uses YAML frontmatter to configure models for codex and gemini invocations.
Use the Bash tool to define the `_resolve_model` helper and resolve models for this session:
_resolve_model() {
local task="$1" provider="$2"
local config="${EMPORIUM_PROVIDERS_CONFIG:-$HOME/.claude/emporium-providers.local.md}"
[ -f "$config" ] || return 0
python3 -c "
import sys, re, os
config_path = os.environ.get('EMPORIUM_PROVIDERS_CONFIG', os.path.expanduser('~/.claude/emporium-providers.local.md'))
try:
with open(config_path) as f:
text = f.read()
except Exception:
sys.exit(0)
# Extract YAML frontmatter
m = re.match(r'^---\s*\n(.*?)\n---', text, re.DOTALL)
if not m:
sys.exit(0)
fm = m.group(1)
# Minimal YAML parser (stdlib only, no PyYAML dependency)
def parse_yaml_flat(lines):
\"\"\"Parse simple nested YAML into dot-separated key dict.\"\"\"
result = {}
stack = [] # (indent_level, key_prefix)
for line in lines:
stripped = line.rstrip()
if not stripped or stripped.startswith('#'):
continue
indent = len(line) - len(line.lstrip())
# pop stack to find parent
while stack and stack[-1][0] >= indent:
stack.pop()
prefix = stack[-1][1] + '.' if stack else ''
if ':' in stripped:
key, _, val = stripped.partition(':')
key = key.strip()
val = val.strip().strip('\"').strip(\"'\")
full_key = prefix + key
if val:
result[full_key] = val
stack.append((indent, full_key))
return result
data = parse_yaml_flat(fm.split('\n'))
task = '$task'
provider = '$provider'
# Resolution order: routing.task.provider -> routing.default.provider -> defaults.provider.model
model = ''
for lookup in [f'routing.{task}.{provider}', f'routing.default.{provider}', f'defaults.{provider}.model']:
if lookup in data:
model = data[lookup]
break
# Validate model name
if model and not re.match(r'^[A-Za-z0-9._:-]+\$', model):
model = ''
print(model)
" 2>/dev/null
}
SIGNUM_CODEX_MODEL=$(_resolve_model "review" "codex")
SIGNUM_GEMINI_MODEL=$(_resolve_model "review" "gemini")
SIGNUM_CODEX_PROFILE="${SIGNUM_CODEX_PROFILE:-}"
echo "codex_model=${SIGNUM_CODEX_MODEL:-(cli default)} gemini_model=${SIGNUM_GEMINI_MODEL:-(cli default)} codex_profile=${SIGNUM_CODEX_PROFILE:-(none)}"Save `SIGNUM_CODEX_MODEL` and `SIGNUM_GEMINI_MODEL` for use in all subsequent codex/gemini invocations. If either is empty, do NOT pass `--model` — let the CLI use its built-in default.
Use the `PROJECT_ROOT` determined during Project Resolution. Verify we are in the correct directory:
Check for a resumable working set using `contracts/index.json` first. Root `.signum/contract.json` is only a legacy fallback during the migration:
source lib/contract-dir.sh
RESUME_INFO=$(describe_active_contract_state)
RESUME_STATE=$(printf '%s' "$RESUME_INFO" | jq -r '.state')
RESUME_CONTRACT_ID=$(printf '%s' "$RESUME_INFO" | jq -r '.contractId // empty')
RESUME_STATUS=$(printf '%s' "$RESUME_INFO" | jq -r '.status // empty')
if [ "$RESUME_STATE" = "NONE" ] && [ -f .signum/contract.json ] && [ ! -L .signum/contract.json ]; then
if [ -f .signum/execution_context.json ] && [ ! -L .signum/execution_context.json ]; then
RESUME_STATE="LEGACY_RESUMABLE"
else
RESUME_STATE="LEGACY_CONTRACT_ONLY"
fi
fi
jq -n \
--arg state "$RESUME_STATE" \
--arg contractId "$RESUME_CONTRACT_ID" \
--arg status "$RESUME_STATUS" \
'{
state: $state,
contractId: (if $contractId == "" then null else $contractId end),
status: (if $status == "" then null else $status end)
}'- If `.state == "RESUMABLE"`: an active contract exists in `contracts/index.json`. Ask the user: "Active contract `<contractId>` is in progress. Resume from Phase 2, or restart from Phase 1 (discards the active working set)?"
- If `.state == "CONTRACT_ONLY"`: an active contract exists but execution has not started. Ask: "Active contract `<contractId>` exists but execution has not started. Resume from Phase 2, or restart from Phase 1 (new contract)?"
- If `.state == "LEGACY_RESUMABLE"` or `.state == "LEGACY_CONTRACT_ONLY"`: a legacy root-based working set exists outside the contract registry. Ask: "A legacy `.signum/` working set was found. Resume by migrating it into `.signum/contracts/`, or restart from Phase 1?"
- If `.state == "NONE"`: proceed to Phase 1.
If the user chooses to resume a legacy root-based working set, migrate it into the canonical active contract directory before continuing:
source lib/contract-dir.sh LEGACY_CONTRACT_ID=$(jq -r '.contractId // empty' .signum/contract.json 2>/dev/null || true) if [ -z "$LEGACY_CONTRACT_ID" ] || [ "$LEGACY_CONTRACT_ID" = "null" ]; then LEGACY
Signum is a contract-first proof gate for agentic software changes: it turns a task into a reviewed contract, executes against that contract, audits the result, and packages evidence that humans and CI can inspect.
Other commands on signum.
- /apply
Implement tasks from an OpenSpec change (Experimental)
Open command - /archive
Archive a completed change in the experimental workflow
Open command - /explore
Enter explore mode - think through ideas, investigate problems, clarify requirements
Open command - /propose
Propose a new change - create it and generate all artifacts in one step
Open command - /sync
Sync delta specs from a change to main specs
Open command - /update
Update a change - revise existing planning artifacts and keep them coherent (Experimental)
Open command

