POS includes 21 shell scripts that power the system. All scripts live in the scripts/ directory and require Bash 3.2+.
Run any script from the repository root:
./scripts/<script-name>.sh [arguments]Scripts that initialize your instance and generate files from configuration.
Purpose: Interactive setup for a new POS instance.
Usage:
./scripts/pos-init.sh # Interactive setup
./scripts/pos-init.sh --defaults # Use defaults (for testing/CI)What it does:
- Asks for your name, timezone, and first work context
- Creates
pos.yamlfrom your answers - Creates directory structure (
contexts/,.handoff/,.state/) - Creates
status.yamlandQUICK-START.mdfor each context - Runs
pos-generate.shto createAGENTS.mdandCLAUDE.md - Runs
sync-state.shto create.state/snapshot.yaml
Example:
$ ./scripts/pos-init.sh
============================================
Personal Operating System (POS) Setup
============================================
Your name [User]: Jane Smith
Your timezone [UTC]: America/New_York
...
POS initialized successfully!If pos.yaml already exists, the script exits with a warning. Delete pos.yaml to start fresh, or use pos-generate.sh to regenerate docs.
Purpose: Regenerate AGENTS.md and CLAUDE.md from templates and pos.yaml.
Usage:
./scripts/pos-generate.sh # Generate both
./scripts/pos-generate.sh agents # Generate AGENTS.md only
./scripts/pos-generate.sh claude # Generate CLAUDE.md onlyWhat it does:
- Reads
pos.yamlfor configuration values - Reads
templates/AGENTS.md.tmplandtemplates/CLAUDE.md.tmpl - Replaces
{{PLACEHOLDER}}markers with values from config - Writes
AGENTS.mdand/orCLAUDE.mdto the repository root
Example:
$ ./scripts/pos-generate.sh
Generated: AGENTS.md
Generated: CLAUDE.mdRun this after every change to pos.yaml.
Purpose: Shared config reader sourced by other scripts. Not run directly.
Usage:
source "$(dirname "$0")/pos-config.sh"What it provides:
REPO_ROOT-- absolute path to the repository rootPOS_CONFIG-- path topos.yamlCONTEXTS_DIR-- path tocontexts/yval()-- extract simple YAML values from a fileyval_nested()-- extract one-level nested YAML valuesget_context_path()-- get the filesystem path for a context IDget_context_stack()-- get the tech stack for a context IDstack_to_capability()-- map a stack name to a capability type
Scripts that manage the skill template system.
Purpose: Generate SKILL.md from SKILL.md.tmpl templates with shared partials.
Usage:
./scripts/generate-skills.sh # Generate all skills
./scripts/generate-skills.sh my-skill # Generate one skill
./scripts/generate-skills.sh --dry-run # Check for drift (exit 1 if stale)What it does:
- Finds all skill directories in
.claude/skills/ - For each directory with a
SKILL.md.tmpl, replaces{{PREAMBLE}},{{COMMON_RULES}},{{OUTPUT_FORMAT}}, and{{SELF_RATING}}with content fromtemplates/skills/partials/ - Writes the result to
SKILL.md - In
--dry-runmode, compares generated output against existing files without writing
Example:
$ ./scripts/generate-skills.sh
Generating skills from templates...
GEN code-review
GEN plan-generation
GEN session
---
Generated: 3 | Skipped (no template): 1
Done.$ ./scripts/generate-skills.sh --dry-run
Checking skill template freshness...
OK code-review
STALE plan-generation
---
Stale: 1 | Skipped (no template): 1
Drift detected. Run ./scripts/generate-skills.sh to regenerate.Purpose: Create portable .skills/*.md files from Claude Code skills, with frontmatter stripped.
Usage:
./scripts/generate-portable-skills.shWhat it does:
- Reads each
.claude/skills/{name}/SKILL.md - Strips the YAML frontmatter (everything between
---delimiters) - Writes the remaining markdown to
.skills/{name}.md
Example:
$ ./scripts/generate-portable-skills.sh
Generated 5 portable skill files in .skills/Purpose: Static validation for all skill files. Catches broken skills before they reach users.
Usage:
./scripts/validate-skills.sh # Validate all skills
./scripts/validate-skills.sh my-skill # Validate one skillWhat it checks:
SKILL.mdexists in the skill directory- File starts with valid YAML frontmatter (
---) namefield exists and matches the directory namedescriptionfield existsallowed-toolscontains only recognized tool names- No unresolved
{{PLACEHOLDER}}markers - Line count is under 500 (warning)
Example:
$ ./scripts/validate-skills.sh
Validating POS skills...
OK code-review
OK session
FAIL broken-skill (1 errors)
ERROR: Missing 'description' in frontmatter
---
Checked: 3 | Errors: 1 | Warnings: 0
Validation FAILEDExit code 0 = all checks pass. Exit code 1 = errors found.
Scripts that manage the AI session lifecycle.
Purpose: Register a new AI tool or model session.
Usage:
./scripts/session-register.sh <agent-id> [context] [capability-level]Arguments:
agent-id-- Name for the AI tool (e.g.,claude-code,cursor,gemini-pro)context-- Which work context to focus on (default:unspecified)capability-level-- Self-assessed capability:basic,standard,advanced,reasoning(default:standard)
What it does:
- Creates
.handoff/sessions/{agent-id}.yamlwith session metadata - If a session file already exists for this agent, overwrites it with a warning
- Runs
sync-state.shto update.state/snapshot.yaml
Example:
$ ./scripts/session-register.sh "claude-code" "dayjob" "reasoning"
Session registered: claude-code
Context: dayjob
Capability: reasoning
File: .handoff/sessions/claude-code.yaml
When done, run: ./scripts/session-close.sh "claude-code"Purpose: Close a session and create a handoff record.
Usage:
./scripts/session-close.sh <agent-id> [summary]Arguments:
agent-id-- The same agent ID used when registeringsummary-- What was accomplished (default:"Session ended without summary")
What it does:
- Reads session data from
.handoff/sessions/{agent-id}.yaml - Creates a handoff record at
.handoff/handoffs/{date}-{agent-id}.yaml - Removes the session file
- Removes any plan lock files (
.claude/.plan-lock-*) - Runs
sync-state.shandsync-queue.sh
Example:
$ ./scripts/session-close.sh "claude-code" "Implemented OAuth login flow"
Session closed: claude-code
Handoff: .handoff/handoffs/2026-03-19-claude-code.yaml
Duration: 2026-03-19T09:00:00Z → 2026-03-19T11:30:00Z
Context: dayjobIf multiple sessions close on the same day from the same agent, the script appends a counter (e.g., 2026-03-19-claude-code-2.yaml).
Purpose: Create an ad-hoc task file from a template.
Usage:
./scripts/create-task.sh <context> "<task-title>"What it does:
- Creates a task file at
contexts/{context}/tasks/{date}-{slug}.mdfromtemplates/task.md - Substitutes title, context name, and date into the template
Example:
$ ./scripts/create-task.sh dayjob "Fix login redirect bug"
Task created: contexts/dayjob/tasks/2026-03-19-fix-login-redirect-bug.mdPurpose: Start working on a task from the queue.
Usage:
./scripts/task-start.sh <task-id> <context> <agent-id>What it does:
- Logs the task claim to
.handoff/claims.log - Creates a session file if one does not exist
- Creates a handoff placeholder file
- Runs a health check in the background
Example:
$ ./scripts/task-start.sh DAYJOB-RESUME dayjob claude-code
Starting task DAYJOB-RESUME for team dayjob...
Task claimed in queue log: .handoff/claims.log
Session registered at .handoff/sessions/claude-code.yaml
Handoff updated at .handoff/handoffs/2026-03-19-dayjob-claude-code-DAYJOB-RESUME.yaml
Task DAYJOB-RESUME started successfully!Purpose: Mark a task as complete and update the handoff record.
Usage:
./scripts/task-complete.sh <handoff-id> "<summary>"What it does:
- Appends completion timestamp and resolution summary to the handoff file
- Logs completion to
.handoff/claims.log
Example:
$ ./scripts/task-complete.sh 2026-03-19-dayjob-claude-code-DAYJOB-RESUME "Fixed the OAuth redirect and added tests"
Completing task for handoff 2026-03-19-dayjob-claude-code-DAYJOB-RESUME...
Handoff file updated.
Queue log updated.
REMINDER: If you are done for the day, run ./scripts/session-close.shScripts that aggregate status, manage the task queue, and check system health.
Purpose: Aggregate all context status into .state/snapshot.yaml.
Usage:
./scripts/sync-state.shWhat it does:
- Scans all
contexts/*/status.yamlfiles - Reads all session files in
.handoff/sessions/ - Counts queue tasks from
.handoff/queue.yaml - Writes a unified view to
.state/snapshot.yaml
Example:
$ ./scripts/sync-state.sh
State synced to .state/snapshot.yaml (1 active sessions, 1 registered agents)This runs automatically when sessions are registered or closed.
Purpose: Populate .handoff/queue.yaml from context status files.
Usage:
./scripts/sync-queue.shWhat it does:
- Scans all context
status.yamlfiles forresume_pointentries - Creates a task for each context with a pending resume point
- Maps the context stack to a capability type
- Skips contexts with active sessions
- Writes the queue with inline
quick_contextfor each task
Example:
$ ./scripts/sync-queue.sh
Queue synced: 2 tasks from context status filesPurpose: Run health checks on a specific context.
Usage:
./scripts/check-health.sh <context>
./scripts/check-health.sh <context> quiet # Suppress OK messagesWhat it checks:
- Status file size (warns if over 10KB)
- PROJECT_INDEX.yaml exists in each git project
- Skill validation passes
- Skill templates are not stale
Example:
$ ./scripts/check-health.sh dayjob
Checking health for context: dayjob
OK: Status file size (2KB)
OK: Project Indices
OK: Skill validation
OK: Skill templates up to date
System Health: GOODPurpose: Cron-compatible daily sync of state and queue.
Usage:
./scripts/daily-sync.shWhat it does:
- Runs
sync-state.sh - Runs
sync-queue.sh - Appends a timestamped log entry to
.state/sync.log
Example crontab entry:
0 22 * * * /path/to/repo/scripts/daily-sync.sh
Purpose: Move completed items from status.yaml to a monthly archive file.
Usage:
./scripts/archive-status.sh <context>What it does:
- Reads
completed_todayentries fromcontexts/{context}/status.yaml - Appends them to
contexts/{context}/logs/status-archive-{YYYY-MM}.yaml - Clears
completed_todayin the status file
Example:
$ ./scripts/archive-status.sh dayjob
Archiving status for dayjob...
Appended completed items to contexts/dayjob/logs/status-archive-2026-03.yaml
Cleared completed_today in contexts/dayjob/status.yaml
Archive complete.Purpose: Summarize skill self-rating feedback.
Usage:
./scripts/aggregate-feedback.sh # Summary only
./scripts/aggregate-feedback.sh --detail # Include individual entriesWhat it does:
- Reads all
.handoff/feedback/*.yamlfiles - Calculates average rating per skill and overall
- Optionally shows individual feedback entries
Example:
$ ./scripts/aggregate-feedback.sh
=== Skill Feedback Summary ===
Total entries: 8
Average rating: 7/10
SKILL AVG ENTRIES
----- --- -------
code-review 8/10 3
plan-generation 6/10 5Purpose: Cross-skill artifact persistence helpers. Sourced by other scripts, not run directly.
Usage:
source scripts/lib-artifacts.shFunctions provided:
artifact_write <skill> <context> <type> <content_file> [branch]artifact_find <context> <type> [skill]artifact_list <context>artifact_archive <context> <branch>artifact_cleanup [days]
See the Skills Guide for details.
Scripts that enforce workflow rules and manage repositories.
Purpose: PreToolUse hook that blocks code edits without an approved plan.
Usage: Called automatically by the Claude Code PreToolUse hook. Not run directly.
What it does:
- Checks if the file being edited is under
contexts/{id}/projects/ - If so, checks for a lock file at
.claude/.plan-lock-{context} - Blocks the edit if no lock file exists, with a message explaining how to approve a plan
Non-project files (status.yaml, plans, handoffs, CLAUDE.md) are never blocked.
Purpose: Approve a plan and unlock code edits for a context.
Usage:
./scripts/approve-plan.sh <plan-file-path>What it does:
- Verifies the plan file exists
- Extracts the context name from the file path
- Creates
.claude/.plan-lock-{context}with plan metadata
Example:
$ ./scripts/approve-plan.sh contexts/dayjob/plans/sprints/sprint-1-auth.yaml
Plan approved and code edits unlocked for context: dayjob
Plan: contexts/dayjob/plans/sprints/sprint-1-auth.yaml
Lock: .claude/.plan-lock-dayjobLock files are automatically removed when a session closes.
Purpose: Git repository management across contexts. Clone, sync, and verify repos.
Usage:
./scripts/repo-manager.sh setup <context> # Clone all repos for a context
./scripts/repo-manager.sh sync <context> # Pull latest changes
./scripts/repo-manager.sh status <context> # Check repo status
./scripts/repo-manager.sh verify <context> # Verify repo integrity
./scripts/repo-manager.sh clone <context> # Clone specific reposWhat it does:
- Reads repository definitions from a platform registry file
- Clones repositories into
contexts/{id}/projects/ - Pulls latest changes across all repos
- Reports status (branch, uncommitted changes, ahead/behind)
Example:
$ ./scripts/repo-manager.sh status dayjob
Checking repos for dayjob...
my-api: main (clean, up to date)
my-frontend: feature/login (+2 ahead, 1 uncommitted)| Script | Category | One-Line Purpose |
|---|---|---|
pos-init.sh |
Setup | Interactive setup for new instances |
pos-generate.sh |
Setup | Regenerate AGENTS.md/CLAUDE.md from config |
pos-config.sh |
Setup | Shared config reader (sourced by other scripts) |
generate-skills.sh |
Skills | Generate SKILL.md from templates |
generate-portable-skills.sh |
Skills | Create portable .skills/*.md for non-Claude tools |
validate-skills.sh |
Skills | Static validation for skill files |
session-register.sh |
Sessions | Register an AI session |
session-close.sh |
Sessions | Close session and create handoff |
create-task.sh |
Sessions | Create an ad-hoc task file |
task-start.sh |
Sessions | Start a task from the queue |
task-complete.sh |
Sessions | Mark a task as complete |
sync-state.sh |
State | Aggregate status into snapshot.yaml |
sync-queue.sh |
State | Populate task queue from context status |
check-health.sh |
State | System health checks |
daily-sync.sh |
State | Cron-compatible daily sync |
archive-status.sh |
State | Prune bloated status files |
aggregate-feedback.sh |
State | Summarize skill feedback |
lib-artifacts.sh |
State | Cross-skill artifact helpers (sourced) |
plan-gate.sh |
Workflow | Block edits without approved plan (hook) |
approve-plan.sh |
Workflow | Approve a plan and unlock edits |
repo-manager.sh |
Workflow | Git repo management across contexts |