@sous-io/sous 0.1.0

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.
Files changed (82) hide show
  1. package/LICENSE +201 -0
  2. package/README.md +154 -0
  3. package/bin/run.js +17 -0
  4. package/bin/xcv +5 -0
  5. package/package.json +81 -0
  6. package/shared-prompts/_partials/resume-task.md +51 -0
  7. package/shared-prompts/_partials/sub-agent-delegation.md +32 -0
  8. package/shared-prompts/_partials/update-task-file.md +52 -0
  9. package/shared-prompts/memories/automated-browser-tasks/INDEX.tpl.md +52 -0
  10. package/shared-prompts/skills/automated-browser-tasks/about-automated-browser-tasks/SKILL.tpl.md +102 -0
  11. package/shared-prompts/skills/automated-browser-tasks/about-automated-browser-tasks/examples/auth-failure-handling.mjs +81 -0
  12. package/shared-prompts/skills/automated-browser-tasks/about-automated-browser-tasks/examples/chained-workflow.mjs +126 -0
  13. package/shared-prompts/skills/automated-browser-tasks/about-automated-browser-tasks/examples/simple-fetch.mjs +92 -0
  14. package/shared-prompts/skills/automated-browser-tasks/about-automated-browser-tasks/references/architecture.md +61 -0
  15. package/shared-prompts/skills/automated-browser-tasks/about-automated-browser-tasks/references/auth-and-sessions.md +65 -0
  16. package/shared-prompts/skills/automated-browser-tasks/about-automated-browser-tasks/references/ctx-api.md +96 -0
  17. package/shared-prompts/skills/automated-browser-tasks/about-automated-browser-tasks/references/installation.md +104 -0
  18. package/shared-prompts/skills/automated-browser-tasks/about-automated-browser-tasks/references/script-conventions.md +243 -0
  19. package/shared-prompts/skills/automated-browser-tasks/about-automated-browser-tasks/scripts/chrome-state.mjs +148 -0
  20. package/shared-prompts/skills/automated-browser-tasks/about-automated-browser-tasks/scripts/debug.mjs +383 -0
  21. package/shared-prompts/skills/automated-browser-tasks/about-automated-browser-tasks/scripts/debug.spec.mjs +267 -0
  22. package/shared-prompts/skills/automated-browser-tasks/about-automated-browser-tasks/scripts/eslint.config.mjs +56 -0
  23. package/shared-prompts/skills/automated-browser-tasks/about-automated-browser-tasks/scripts/harness.mjs +169 -0
  24. package/shared-prompts/skills/automated-browser-tasks/about-automated-browser-tasks/scripts/keyring.mjs +59 -0
  25. package/shared-prompts/skills/automated-browser-tasks/about-automated-browser-tasks/scripts/logger.mjs +25 -0
  26. package/shared-prompts/skills/automated-browser-tasks/about-automated-browser-tasks/scripts/params.mjs +140 -0
  27. package/shared-prompts/skills/automated-browser-tasks/about-automated-browser-tasks/scripts/run.mjs +140 -0
  28. package/shared-prompts/skills/automated-browser-tasks/about-automated-browser-tasks/scripts/settings.tpl.mjs +1 -0
  29. package/shared-prompts/skills/automated-browser-tasks/about-automated-browser-tasks/scripts/utils.mjs +185 -0
  30. package/shared-prompts/skills/automated-browser-tasks/create-automated-browser-task/SKILL.tpl.md +52 -0
  31. package/shared-prompts/skills/automated-browser-tasks/running-automated-browser-tasks/SKILL.tpl.md +59 -0
  32. package/shared-prompts/skills/automated-browser-tasks/update-automated-browser-task/SKILL.tpl.md +47 -0
  33. package/shared-prompts/skills/control-flow/approve/SKILL.tpl.md +26 -0
  34. package/shared-prompts/skills/control-flow/opine/SKILL.tpl.md +58 -0
  35. package/shared-prompts/skills/control-flow/repeat/SKILL.tpl.md +27 -0
  36. package/shared-prompts/skills/control-flow/research/SKILL.tpl.md +34 -0
  37. package/shared-prompts/skills/sous-skills/about-agent-skills/SKILL.tpl.md +177 -0
  38. package/shared-prompts/skills/sous-skills/about-agent-skills/examples/about-something.md +45 -0
  39. package/shared-prompts/skills/sous-skills/about-agent-skills/examples/do-something.md +33 -0
  40. package/shared-prompts/skills/sous-skills/about-agent-skills/references/advanced-patterns.md +87 -0
  41. package/shared-prompts/skills/sous-skills/about-agent-skills/references/commands.md +46 -0
  42. package/shared-prompts/skills/sous-skills/about-agent-skills/references/frontmatter.md +25 -0
  43. package/shared-prompts/skills/sous-skills/about-agent-skills/references/substitutions.md +50 -0
  44. package/shared-prompts/skills/sous-skills/about-liquid-templates/SKILL.tpl.md +268 -0
  45. package/shared-prompts/skills/sous-skills/about-liquid-templates/references/liquid-filters.md +82 -0
  46. package/shared-prompts/skills/sous-skills/about-sous/SKILL.tpl.md +51 -0
  47. package/shared-prompts/skills/sous-skills/create-skill/SKILL.tpl.md +114 -0
  48. package/shared-prompts/skills/task-files/about-task-files/SKILL.tpl.md +122 -0
  49. package/shared-prompts/skills/task-files/continue-task-in-new-branch/SKILL.tpl.md +80 -0
  50. package/shared-prompts/skills/task-files/go/SKILL.tpl.md +14 -0
  51. package/shared-prompts/skills/task-files/resume-task/SKILL.tpl.md +13 -0
  52. package/shared-prompts/skills/task-files/start-task/SKILL.tpl.md +93 -0
  53. package/shared-prompts/skills/task-files/update/SKILL.tpl.md +14 -0
  54. package/shared-prompts/skills/task-files/update-task-file/SKILL.tpl.md +13 -0
  55. package/src/base-command.ts +163 -0
  56. package/src/commands/build.ts +196 -0
  57. package/src/commands/clear.ts +71 -0
  58. package/src/commands/compile.ts +95 -0
  59. package/src/commands/launch.ts +111 -0
  60. package/src/commands/prune.ts +48 -0
  61. package/src/lib/build-service.ts +258 -0
  62. package/src/lib/config-discovery.ts +199 -0
  63. package/src/lib/env-local.ts +195 -0
  64. package/src/lib/include-resolver.ts +146 -0
  65. package/src/lib/markdown-compiler.ts +580 -0
  66. package/src/lib/pid-service.ts +88 -0
  67. package/src/lib/settings.ts +695 -0
  68. package/src/lib/state.ts +135 -0
  69. package/src/lib/watch-service.ts +115 -0
  70. package/src/templating/filters/bullet-list.ts +9 -0
  71. package/src/templating/filters/index.ts +8 -0
  72. package/src/templating/init-liquid-engine.ts +82 -0
  73. package/src/templating/lib/glob-files.ts +74 -0
  74. package/src/templating/lib/import-export.ts +32 -0
  75. package/src/templating/lib/tag-args.ts +19 -0
  76. package/src/templating/tags/exportScalarVarsJs.ts +43 -0
  77. package/src/templating/tags/getFiles.ts +89 -0
  78. package/src/templating/tags/index.ts +14 -0
  79. package/src/templating/tags/listFiles.ts +54 -0
  80. package/src/templating/tags/showVars.ts +22 -0
  81. package/src/utils/formatting.ts +338 -0
  82. package/src/utils/prompts.ts +19 -0
@@ -0,0 +1,51 @@
1
+ ---
2
+ name: about-sous
3
+ description: >
4
+ YOU MUST load this skill when you cannot edit a file in this project, are asked why
5
+ a file keeps reverting, need to know where the source of truth for any managed file
6
+ lives, or need to understand what this project's configuration system is.
7
+ user-invocable: false
8
+ ---
9
+
10
+ # About Sous
11
+
12
+ Sous (`xcv`) is a CLI tool that compiles markdown templates and manages output files
13
+ for AI coding agents. It reads a central configuration, resolves variables, and
14
+ copies or renders files to their destinations in this project.
15
+
16
+ ## Files You Must Never Edit
17
+
18
+ Sous manages certain files in this project by compiling them from a central source.
19
+ **You must never edit these directly.** Your changes will be silently overwritten the
20
+ next time Sous runs:
21
+
22
+ - `.claude/` — Claude Code configuration, skills, and instructions
23
+ - `.codex/` — Codex configuration and skills
24
+ - `AGENTS.md` and `CLAUDE.md` — agent instruction files
25
+ - Any file you did not create yourself in a designated source directory
26
+
27
+ If you need to change something in one of these files, the change must be made at the
28
+ source — in the central configuration this project uses with Sous.
29
+
30
+ ## Where Your Skills Live
31
+
32
+ Skills for this project live at `{{ skillsRoot }}`. That is the source directory Sous
33
+ compiles from. Create and edit skills there — never in `.claude/skills/` or
34
+ `.codex/skills/` directly.
35
+
36
+ YOU MUST load `create-skill` when creating a new skill for this project.
37
+
38
+ ## Sous's Shared Skill Bundles
39
+
40
+ Sous ships shared skill bundles at `{{ sousRootPath }}/shared-prompts/skills/`, which is
41
+ where the `about-sous`, `about-agent-skills` and `about-liquid-templates` skills you are
42
+ reading came from. Edit them only in the sous repository itself, where they are the
43
+ sources. Never edit a compiled copy of them inside a consuming project — that copy is
44
+ build output and is overwritten on the next Sous run.
45
+
46
+ ## Source for this Skill
47
+
48
+ This skill was pulled from the `sous` project's "shared skills" library. It was compiled from a template and
49
+ the output file should not be edited directly.
50
+
51
+ - Source Path: {{ sousTemplatePath }}
@@ -0,0 +1,114 @@
1
+ ---
2
+ name: create-skill
3
+ description: >
4
+ YOU MUST use this skill when creating a new skill for this project.
5
+ ---
6
+
7
+ # Create a Skill
8
+
9
+ The agent performing this work MUST load `about-agent-skills` for skill structure,
10
+ frontmatter, and architecture principles.
11
+
12
+ Skills for this project live at `{{ skillsRoot }}`. Create new skills there — not in
13
+ `.claude/skills/` or `.codex/skills/` directly (those are managed automatically and
14
+ must not be edited).
15
+
16
+ ## Steps
17
+
18
+ ### 1. Create the directory
19
+
20
+ ```
21
+ {{ skillsRoot }}/<skill-name>/
22
+ ```
23
+
24
+ The directory name must match the `name` frontmatter field (lowercase, hyphens).
25
+
26
+ **If `{{ skillsRoot }}` is a bundle root**, its immediate subdirectories are *bundles*, not
27
+ skills, and the path gains a segment: `{{ skillsRoot }}/<bundle-name>/<skill-name>/`. Check
28
+ what is already there before creating anything: a directory holding `SKILL.md` /
29
+ `SKILL.tpl.md` files directly means skills go at the top level; a directory holding further
30
+ subdirectories that each contain a skill means you are looking at bundles, so add the skill
31
+ to the bundle it belongs to. When a new skill genuinely needs a new bundle, create the
32
+ bundle directory and add a matching `entryGlob` target in the config of every project that
33
+ should receive it — a bundle with no `entryGlob` is never compiled anywhere.
34
+
35
+ ### 2. Write `SKILL.tpl.md`
36
+
37
+ Create `SKILL.tpl.md` in the directory with valid frontmatter and an imperative body.
38
+ See `about-agent-skills` for the full frontmatter reference and topic vs action
39
+ skill guidance.
40
+
41
+ **Distributed skills take extended frontmatter.** A skill compiled out to other projects
42
+ declares its provenance and portability; a project-local skill omits these fields because
43
+ nothing outside the project consumes it:
44
+
45
+ ```yaml
46
+ license: MIT
47
+ compatibility:
48
+ - claude
49
+ - codex
50
+ metadata:
51
+ version: 1.0.0
52
+ tags: [<relevant>, <tags>]
53
+ ```
54
+
55
+ ### 3. Add supporting files (if needed)
56
+
57
+ - `references/` — supplementary documentation loaded on demand
58
+ - `scripts/` — executable scripts the skill uses
59
+ - `examples/` — example outputs
60
+
61
+ Reference all supporting files from `SKILL.md` — the agent will not discover them
62
+ otherwise.
63
+
64
+ ### 4. Name the main file `SKILL.tpl.md` and add the source footer
65
+
66
+ Skills in `{{ skillsRoot }}` are compiled and distributed — the main skill file must
67
+ always be named `SKILL.tpl.md`, not `SKILL.md`. No exceptions, and specifically **not even
68
+ when the skill body contains no variables at all**: the mandatory `## Source for this Skill`
69
+ footer itself contains a template variable, so every skill needs a LiquidJS render pass by
70
+ definition. A plain `SKILL.md` is copied verbatim, which would ship the footer's unrendered
71
+ variable straight into the output. The footer:
72
+
73
+ {% raw %}
74
+ ```markdown
75
+ ## Source for this Skill
76
+
77
+ This skill was compiled from a template and the output file should not be edited directly.
78
+
79
+ - Source Path: {{ sousTemplatePath }}
80
+ ```
81
+ {% endraw %}
82
+
83
+ The `{{ sousTemplatePath }}` variable renders to the absolute path of the source template
84
+ at compile time, telling agents where the skill originated.
85
+
86
+ For other files in the skill directory (references, scripts, supporting docs), use `.tpl.`
87
+ naming only when the file genuinely needs LiquidJS processing. YOU MUST load
88
+ `about-liquid-templates` before making that decision.
89
+
90
+ ### 5. No build step needed
91
+
92
+ Once the files exist in `{{ skillsRoot }}`, distribution is handled automatically.
93
+
94
+ ### 6. Write the body for whoever executes it
95
+
96
+ Per the sub-agent delegation pattern
97
+ (`~sous-shared/_partials/sub-agent-delegation.md`), a skill's steps may run in a delegated
98
+ sub-agent with fresh context. Mark which steps are delegated and which are
99
+ orchestrator-only (anything needing the user or this conversation's contents), and
100
+ phrase skill-loading requirements as "The agent performing this work MUST load `x`".
101
+ See `about-agent-skills` → General Principles.
102
+
103
+ # Related Skills
104
+
105
+ YOU MUST load `about-agent-skills` for skill structure and principles. YOU MUST load
106
+ `about-sous` for context on what is managed automatically in this project. YOU MUST
107
+ load `about-liquid-templates` if any file in your skill needs `.tpl.` processing.
108
+
109
+ ## Source for this Skill
110
+
111
+ This skill was pulled from the `sous` project's "shared skills" library. It was compiled from a template and
112
+ the output file should not be edited directly.
113
+
114
+ - Source Path: {{ sousTemplatePath }}
@@ -0,0 +1,122 @@
1
+ ---
2
+ name: about-task-files
3
+ description: YOU MUST load this skill when working with task files — including creating, reading, updating, or archiving a task file, or any time you need to know where task files live.
4
+ user-invocable: false
5
+ ---
6
+
7
+ A **task file** is a Markdown document that tracks a unit of work across one or more chat sessions. It is the single source of truth for what has been done, what remains, and what decisions were made.
8
+
9
+ ## Who Reads and Writes It
10
+
11
+ Per the sub-agent delegation pattern (`~sous-shared/_partials/sub-agent-delegation.md`), reading and
12
+ writing task files is delegated work: the orchestrator supplies the facts and decisions, and a
13
+ sub-agent loads this skill and does the edit.
14
+ Sub-agents start with fresh context and cannot see the chat conversation, so a delegating prompt
15
+ must state any fact that exists only in the conversation. Anything the sub-agent can gather itself
16
+ (branch name, commits, changed files, error output) should be gathered by the sub-agent.
17
+
18
+ ## Location and Naming
19
+
20
+ Task files live at:
21
+ ```
22
+ {{ taskFileRoot }}/[branch-name].md
23
+ ```
24
+
25
+ The filename mirrors the full git branch name — including any `/` separators as path separators:
26
+ - Branch `{{ featureBranchPrefix }}{{ ticketIdExample }}-some-feature` → `{{ taskFileRoot }}/{{ featureBranchPrefix }}{{ ticketIdExample }}-some-feature.md`
27
+
28
+ To find the current task file: run `git status`, take the branch name, construct the path above.
29
+
30
+ **If the file is not found:** run a fresh `git status` to confirm the branch name before concluding it doesn't exist.
31
+
32
+ ## Archive Location
33
+
34
+ Completed task files are archived at:
35
+ ```
36
+ {{ taskFileRoot }}/archive/[branch-name].md
37
+ ```
38
+
39
+ The path structure mirrors the task file location — just under `archive/`.
40
+
41
+ ## Completion Procedure
42
+
43
+ When the user confirms a task is 100% complete:
44
+ 1. Update the task file with the final status
45
+ 2. Move it to `{{ taskFileRoot }}/archive/[branch-name].md` (create subdirectories as needed)
46
+ 3. Switch to the project's main development branch and follow its branch-switching procedures
47
+
48
+ ## File Format
49
+
50
+ ```markdown
51
+ # Task: [Feature/Fix Description]
52
+
53
+ **Branch:** `{{ featureBranchPrefix }}{{ ticketIdExample }}-feature-name`
54
+ **Status:** In Progress - Phase 2 Complete
55
+ **Started:** YYYY-MM-DD
56
+ **Updated:** YYYY-MM-DD
57
+
58
+ ## Overview
59
+ [Brief description of the task objective]
60
+
61
+ ## Current Status
62
+ - Phase 1: Complete
63
+ - Phase 2: Complete
64
+ - Phase 3: In Progress
65
+
66
+ ## Recent Progress
67
+ [What was accomplished in the most recent session]
68
+
69
+ ## Decisions Made
70
+ [Technical and process decisions, with brief rationale]
71
+
72
+ ## Remaining Work
73
+ - [ ] Task with context
74
+ - [ ] Another task
75
+
76
+ ## Pending Issues
77
+ [Unresolved problems, blockers, open questions]
78
+
79
+ ## Key Learnings
80
+ [Patterns, discoveries, gotchas worth remembering]
81
+
82
+ ## Commits Made
83
+ - `abc123f` - description
84
+
85
+ ## Files Modified
86
+ - /absolute/path/to/File.ts:45 - what changed and why
87
+
88
+ ## Testing URLs
89
+ - http://localhost:5173/path/to/page
90
+
91
+ ## Unresolved Errors
92
+ [Test failures, build errors, TypeScript errors — with paths and line numbers]
93
+ ```
94
+
95
+ ## Style Guidelines
96
+
97
+ - No emojis or emoticons
98
+ - Concise but not aggressively compressed — important information must not be lost
99
+ - Wrap long lines at 120 characters
100
+ - Absolute paths with line numbers for file references (not ranges)
101
+ - Use `file:/absolute/path/to/File.ts:45` format for clickable links (two slashes, not three)
102
+
103
+ ## File Size
104
+
105
+ Task files must not exceed **1,000 lines**. When approaching the limit, condense:
106
+ - Completed phases (keep summary, drop detail)
107
+ - Historical context no longer relevant to upcoming work
108
+ - Information less important to immediate next steps
109
+
110
+ Always preserve in full: current active work, immediate next steps, unresolved issues, recent learnings, recently modified files.
111
+
112
+ ## Task Plan Structure
113
+
114
+ When drafting a task plan, segregate work by architectural layer. Work one layer at a time and
115
+ commit at least once per layer.
116
+
117
+ ## Source for this Skill
118
+
119
+ This skill was pulled from the `sous` project's "shared skills" library. It was compiled from a template and
120
+ the output file should not be edited directly.
121
+
122
+ - Source Path: {{ sousTemplatePath }}
@@ -0,0 +1,80 @@
1
+ ---
2
+ name: continue-task-in-new-branch
3
+ description: YOU MUST load this skill when an MR has been merged and remaining work needs to continue in a new branch — including "continue this work in a new branch", "create a follow-up branch", "split this into another MR", "move remaining work to a new branch".
4
+ ---
5
+
6
+ The agent performing this work MUST load `about-task-files`.
7
+
8
+ ## Delegation
9
+
10
+ Per the sub-agent delegation pattern (`~sous-shared/_partials/sub-agent-delegation.md`), the
11
+ orchestrator does the git branch work itself (steps 1, 2,
12
+ and 6, which change the working tree it is in) and delegates the task file writing (steps 3, 4, 5)
13
+ to one Opus sub-agent. That sub-agent needs the old and new branch names, the remaining-work list,
14
+ and the patterns/gotchas to carry forward; sub-agents cannot see this conversation, so state them in
15
+ the prompt.
16
+
17
+ ## Steps
18
+
19
+ ### 1. Prepare for Branch Transition
20
+
21
+ Before switching branches, ensure:
22
+ - Current branch is fully pushed to the remote
23
+ - All important context is documented in the current task file (load `update-task-file` if needed)
24
+ - The MR has been merged or is ready to close
25
+
26
+ ### 2. Create the New Branch
27
+
28
+ Name the new branch using the original name plus a letter suffix (`-b`, `-c`, etc.):
29
+ ```bash
30
+ git checkout <main-development-branch>
31
+ git pull origin <main-development-branch>
32
+ git checkout -b {{ featureBranchPrefix }}{{ ticketIdExample }}-description-b
33
+ ```
34
+
35
+ ### 3. Create the New Task File
36
+
37
+ Create `{{ taskFileRoot }}/{{ featureBranchPrefix }}{{ ticketIdExample }}-description-b.md` with:
38
+ - **Task Overview**: brief description and connection to the previous MR
39
+ - **Remaining Work**: clear list of unfinished tasks with enough context to understand each item independently
40
+ - **Key Patterns and Learnings**: essential patterns from the previous branch worth carrying forward
41
+ - **Important Notes**: critical gotchas, blockers, or dependencies
42
+
43
+ Do NOT include: completed tasks (unless essential context), resolved MR comments, detailed change history.
44
+
45
+ ### 4. Update the Old Task File
46
+
47
+ Add a "Work Continuation" section to the old task file before archiving:
48
+
49
+ ```markdown
50
+ ## Work Continuation
51
+ Remaining work has been moved to:
52
+ - **Branch**: {{ featureBranchPrefix }}{{ ticketIdExample }}-description-b
53
+ - **Task File**: {{ taskFileRoot }}/{{ featureBranchPrefix }}{{ ticketIdExample }}-description-b.md
54
+ - **Scope**: [brief description of remaining work]
55
+
56
+ This task file is now archived — work in the associated MR has been completed and merged.
57
+ ```
58
+
59
+ ### 5. Archive the Old Task File
60
+
61
+ ```bash
62
+ mv {{ taskFileRoot }}/{{ featureBranchPrefix }}{{ ticketIdExample }}-description-a.md \
63
+ {{ taskFileRoot }}/archive/{{ featureBranchPrefix }}{{ ticketIdExample }}-description-a.md
64
+ ```
65
+
66
+ Create the archive subdirectory if it doesn't exist.
67
+
68
+ ### 6. Clean Up
69
+
70
+ ```bash
71
+ # Delete the old local branch
72
+ git branch -D {{ featureBranchPrefix }}{{ ticketIdExample }}-description-a
73
+ ```
74
+
75
+ ## Source for this Skill
76
+
77
+ This skill was pulled from the `sous` project's "shared skills" library. It was compiled from a template and
78
+ the output file should not be edited directly.
79
+
80
+ - Source Path: {{ sousTemplatePath }}
@@ -0,0 +1,14 @@
1
+ ---
2
+ name: go
3
+ description: Resume work on the current branch task — load the task file, analyze progress, identify next steps, and present options.
4
+ disable-model-invocation: true
5
+ ---
6
+
7
+ @~sous-shared/_partials/resume-task.md
8
+
9
+ ## Source for this Skill
10
+
11
+ This skill was pulled from the `sous` project's "shared skills" library. It was compiled from a template and
12
+ the output file should not be edited directly.
13
+
14
+ - Source Path: {{ sousTemplatePath }}
@@ -0,0 +1,13 @@
1
+ ---
2
+ name: resume-task
3
+ description: YOU MUST load this skill when the user is resuming work on an existing task — including "resume work", "continue from where we left off", "what's the status?", "what should we do next?", "read the task file", or when starting a new session on a branch that has an existing task file.
4
+ ---
5
+
6
+ @~sous-shared/_partials/resume-task.md
7
+
8
+ ## Source for this Skill
9
+
10
+ This skill was pulled from the `sous` project's "shared skills" library. It was compiled from a template and
11
+ the output file should not be edited directly.
12
+
13
+ - Source Path: {{ sousTemplatePath }}
@@ -0,0 +1,93 @@
1
+ ---
2
+ name: start-task
3
+ description: >
4
+ YOU MUST load this skill when the user wants to start work on a new task — including "start a
5
+ new task", "let's work on {{ ticketIdExample }}", "begin a new task", "create a task file", or
6
+ any request to begin fresh work on a ticket.
7
+ ---
8
+
9
+ The agent performing this work MUST load `about-task-files` and any "about" skills related to the
10
+ project's task management system (e.g. Jira, Linear, etc.).
11
+
12
+ ## Delegation
13
+
14
+ Per the sub-agent delegation pattern (`~sous-shared/_partials/sub-agent-delegation.md`):
15
+
16
+ - **Orchestrator-only:** every step that needs the user (picking the ticket, confirming the branch
17
+ name, approving the plan) and the git branch operations, which change the working tree the
18
+ orchestrator is in.
19
+ - **Delegated:** pulling ticket info (step 2) and writing the task file (step 4), each to a
20
+ background sub-agent. Dispatch them in parallel when independent.
21
+ - Sub-agents return links, questions, and confirmations to the orchestrator, which relays them to
22
+ the user.
23
+
24
+ ## Steps
25
+
26
+ ### 1. Identify the Ticket
27
+
28
+ Look for a ticket identifier (e.g. `{{ ticketIdExample }}`) in the user's message. If none is
29
+ provided:
30
+ - Ask the user to specify one, or offer to help them pick one
31
+ - Once a ticket number is confirmed, proceed
32
+
33
+ ### 2. Pull Ticket Info
34
+
35
+ Delegate to a sub-agent: fetch basic ticket info from the project's task management system and
36
+ report it back. If the ticket doesn't exist, go back to step 1. If unassigned, ask the user if they
37
+ want to assign it to themselves. If the status indicates it hasn't been started, ask if they want to
38
+ transition it to an active state. Those questions are orchestrator-only; the sub-agent reports the
39
+ assignee and status and the orchestrator asks.
40
+
41
+ After transitioning, ensure the issue is visible on the team's board. If the project ships an
42
+ "about" skill for its task management system (e.g. `about-jira`, `about-linear`), follow its
43
+ board-move instructions for the board type and target status.
44
+
45
+ ### 3. Check for an Existing Branch
46
+
47
+ Look for local branches that include the ticket number:
48
+ ```bash
49
+ git branch | grep {{ ticketIdExample }}
50
+ ```
51
+
52
+ If found, confirm it's the right branch with the user (there may be multiple), then:
53
+ ```bash
54
+ git checkout [branch-name]
55
+ git pull origin [branch-name]
56
+ ```
57
+ Then go to step 4.
58
+
59
+ ### 3a. Create a New Branch
60
+
61
+ If no existing branch is found:
62
+
63
+ 1. Switch to the project's main development branch and pull latest
64
+ 2. Resolve branch name: `{{ featureBranchPrefix }}{{ ticketPrefix }}[ticket-number]-[short-description]`
65
+ derived from the ticket title. **Confirm with the user before creating.**
66
+ 3. Create and switch to the branch:
67
+ ```bash
68
+ git checkout -b [branch-name]
69
+ ```
70
+
71
+ ### 4. Load or Create the Task File
72
+
73
+ Check for an existing task file at `{{ taskFileRoot }}/[branch-name].md`.
74
+
75
+ - **Found**: read it, note what's already captured, and continue to step 5
76
+ - **Not found**: delegate to a sub-agent, which collects full ticket info (summary, description,
77
+ status, assignee, related issues, comments, story points, sub-tasks, any linked MRs or commits)
78
+ and creates the task file using the format in `about-task-files`. Include relevant testing URLs
79
+ with real record IDs so URLs are actually clickable. Use `file:/absolute/path:line` format for
80
+ source file links.
81
+
82
+ ### 5. Plan and Start
83
+
84
+ The orchestrator drafts the task plan, organized by layer (see `about-task-files` for layer
85
+ ordering), and asks the user if they want to begin work. Recording the approved plan in the task
86
+ file is delegated; pass the plan text to the sub-agent verbatim.
87
+
88
+ ## Source for this Skill
89
+
90
+ This skill was pulled from the `sous` project's "shared skills" library. It was compiled from a
91
+ template and the output file should not be edited directly.
92
+
93
+ - Source Path: {{ sousTemplatePath }}
@@ -0,0 +1,14 @@
1
+ ---
2
+ name: update
3
+ description: Update the task file before ending the session or when context is running low.
4
+ disable-model-invocation: true
5
+ ---
6
+
7
+ @~sous-shared/_partials/update-task-file.md
8
+
9
+ ## Source for this Skill
10
+
11
+ This skill was pulled from the `sous` project's "shared skills" library. It was compiled from a template and
12
+ the output file should not be edited directly.
13
+
14
+ - Source Path: {{ sousTemplatePath }}
@@ -0,0 +1,13 @@
1
+ ---
2
+ name: update-task-file
3
+ description: YOU MUST load this skill when context is running low, the user is ending the session, or they say "update the task file", "document our progress", "save our state", "prepare for new session", or invoke the !update command.
4
+ ---
5
+
6
+ @~sous-shared/_partials/update-task-file.md
7
+
8
+ ## Source for this Skill
9
+
10
+ This skill was pulled from the `sous` project's "shared skills" library. It was compiled from a template and
11
+ the output file should not be edited directly.
12
+
13
+ - Source Path: {{ sousTemplatePath }}
@@ -0,0 +1,163 @@
1
+ import { Command, Flags } from "@oclif/core";
2
+ import {
3
+ discoverConfig,
4
+ formatNotFoundMessage,
5
+ resolveConfigFlag,
6
+ type DiscoveredConfig,
7
+ } from "./lib/config-discovery.js";
8
+ import { loadEnvFiles } from "./lib/env-local.js";
9
+ import {
10
+ isConfigError,
11
+ loadSettings,
12
+ type ConfigContext,
13
+ type RawProject,
14
+ type Settings,
15
+ } from "./lib/settings.js";
16
+ import { displayError, displayErrorBlock, header } from "./utils/formatting.js";
17
+
18
+ /**
19
+ * Base class for all CLI commands.
20
+ *
21
+ * Startup sequence:
22
+ * 1. Locate the config — `--config <path>` wins, otherwise walk up from cwd
23
+ * looking for a `.sous/` directory holding sous.config.{js,mjs,json}.
24
+ * 2. Load `<.sous>/.env.local`, then `<.sous>/.env`, into process.env (never
25
+ * overwriting real env vars). Precedence: shell > .env.local > .env.
26
+ * 3. Load the config file. Variable resolution happens later, per command.
27
+ *
28
+ * There is no user-level config: nothing is read from `~/.sous`.
29
+ */
30
+ export abstract class BaseCommand extends Command {
31
+ static baseFlags = {
32
+ project: Flags.string({
33
+ char: "p",
34
+ description: "Project key to operate on",
35
+ }),
36
+ config: Flags.string({
37
+ char: "c",
38
+ description:
39
+ "Path to a sous config file (or a directory containing one). Overrides .sous/ discovery",
40
+ }),
41
+ };
42
+
43
+ protected settings!: Settings;
44
+
45
+ /** Where the active config was found. */
46
+ protected configContext!: ConfigContext;
47
+
48
+ /** The full discovery result, including how the config was located. */
49
+ protected discovered!: DiscoveredConfig;
50
+
51
+ async init(): Promise<void> {
52
+ await super.init();
53
+ header();
54
+
55
+ // Read --config off argv directly. oclif's parse() runs inside each command's
56
+ // run(), which is too late: env vars must be injected before any resolution.
57
+ const configFlag = readConfigFlagFromArgv(this.argv);
58
+
59
+ let discovered: DiscoveredConfig | null;
60
+
61
+ if (configFlag !== undefined) {
62
+ try {
63
+ discovered = resolveConfigFlag(configFlag);
64
+ } catch (error) {
65
+ displayError(error instanceof Error ? error.message : String(error));
66
+ return this.exit(1);
67
+ }
68
+ } else {
69
+ discovered = discoverConfig();
70
+ }
71
+
72
+ if (!discovered) {
73
+ displayErrorBlock(formatNotFoundMessage());
74
+ return this.exit(1);
75
+ }
76
+
77
+ this.discovered = discovered;
78
+ this.configContext = {
79
+ sousDir: discovered.sousDir,
80
+ configPath: discovered.configPath,
81
+ };
82
+
83
+ // Inject .sous/.env.local and .sous/.env before anything resolves variables.
84
+ loadEnvFiles(discovered.sousDir);
85
+
86
+ try {
87
+ this.settings = await loadSettings(discovered.configPath);
88
+ } catch (error) {
89
+ displayErrorBlock(error instanceof Error ? error.message : String(error));
90
+ return this.exit(1);
91
+ }
92
+ }
93
+
94
+ /**
95
+ * Renders a configuration error as a plain, readable message instead of an
96
+ * oclif stack trace. The stack for a ConfigError points at Sous internals and
97
+ * tells the user nothing about the config mistake they need to fix.
98
+ *
99
+ * Anything that is not a ConfigError falls through to oclif's normal handling,
100
+ * where a stack trace IS useful (it is a bug in Sous).
101
+ */
102
+ protected async catch(error: Error & { exitCode?: number }): Promise<unknown> {
103
+ if (isConfigError(error)) {
104
+ displayErrorBlock(error.message);
105
+ return this.exit(1);
106
+ }
107
+ return super.catch(error);
108
+ }
109
+
110
+ /**
111
+ * Resolves the active project from the --project flag or settings.defaultProject.
112
+ * Exits with an error if no project key is available or the key is not found.
113
+ */
114
+ protected resolveProject(flagValue: string | undefined): RawProject & { key: string } {
115
+ const keys = Object.keys(this.settings.projects ?? {});
116
+ const key = flagValue ?? this.settings.defaultProject ?? (keys.length === 1 ? keys[0] : undefined);
117
+
118
+ if (!key) {
119
+ displayError(
120
+ "No project specified.\n" +
121
+ ` Config: ${this.configContext.configPath}\n` +
122
+ ` Projects defined: ${keys.length > 0 ? keys.join(", ") : "(none)"}\n` +
123
+ " Use --project <key>, or set defaultProject in your config."
124
+ );
125
+ this.exit(1);
126
+ }
127
+
128
+ const project = this.settings.projects?.[key!];
129
+
130
+ if (!project) {
131
+ displayError(
132
+ `Project '${key}' not found in ${this.configContext.configPath}\n` +
133
+ ` Projects defined: ${keys.length > 0 ? keys.join(", ") : "(none)"}`
134
+ );
135
+ this.exit(1);
136
+ }
137
+
138
+ return { ...project!, key: key! };
139
+ }
140
+
141
+ /** Number of projects defined in the active config. */
142
+ protected get projectCount(): number {
143
+ return Object.keys(this.settings.projects ?? {}).length;
144
+ }
145
+ }
146
+
147
+ /**
148
+ * Pulls the value of `--config` / `-c` out of a raw argv array.
149
+ * Supports `--config X`, `--config=X`, `-c X`, and `-cX`.
150
+ *
151
+ * @param argv - Raw arguments (oclif's `this.argv`, i.e. argv minus the command).
152
+ * @returns The flag value, or undefined when the flag is absent.
153
+ */
154
+ export function readConfigFlagFromArgv(argv: string[]): string | undefined {
155
+ for (let i = 0; i < argv.length; i++) {
156
+ const arg = argv[i];
157
+
158
+ if (arg === "--config" || arg === "-c") return argv[i + 1];
159
+ if (arg.startsWith("--config=")) return arg.slice("--config=".length);
160
+ if (arg.startsWith("-c") && arg.length > 2 && !arg.startsWith("-c-")) return arg.slice(2);
161
+ }
162
+ return undefined;
163
+ }