Justfile Author
Overview
Generate a justfile (and matching Makefile + tx-start helpers) following Nick's
project conventions: zsh shell, DRY parameterized helpers, svc-* tmux service
family wired through cortex tmux, and standard quality recipes
(build, lint, dev, test, typecheck, ci, clean).
When to use this skill
- A repo lacks a justfile and the user wants one.
- A justfile exists but is missing the svc-* family, the Makefile wrapper,
or the standard quality recipes.
- The user asks to add a new service window (e.g.,
svc-worker) to an
existing justfile.
- The user asks to refactor a justfile to be more DRY or to align with
the conventions captured here.
Skip this skill when:
- Editing third-party / open-source justfiles (their conventions own).
- The user has explicitly chosen
make, npm scripts, or another runner
for this project.
Reference example
/Users/nick/Developer/Facet/justfile and /Users/nick/Developer/Facet/Makefile
are the canonical reference. When in doubt, mirror their shape.
Workflow
Step 1 — Inspect the project
Before writing anything, read the project to determine:
- Project slug — derive from the repo directory basename.
- Stack and package manager — what language(s), which lockfile.
- Service catalog — what long-running processes the dev runs locally.
- Existing tooling — what build/test/lint commands the project
already uses (do not invent new ones).
- Runtime activation needs — nvm, asdf, uv, etc.
Consult references/inspection-checklist.md for the full detection table
and the exact slug-normalization rules.
Step 2 — Choose the recipe block
Pull the right language reference into context:
| Stack |
Reference |
| Node |
references/recipes-node.md |
| Rust |
references/recipes-rust.md |
| Python |
references/recipes-python.md |
| Go |
references/recipes-go.md |
For polyglot repos, read multiple references and combine. For stacks not
listed, mirror the structure of the closest listed stack and substitute
the native commands.
Step 3 — Choose the service catalog
Consult references/service-patterns.md for the full svc-* surface area
and the rules for when to add a new service window. Every detected
service gets a parallel pair of recipes (foreground + svc-) and a
tx-start-<role>.sh wrapper.
Step 4 — Emit the files
Use assets/justfile.tmpl, assets/Makefile.tmpl, and
assets/tx-start.sh.tmpl as the structural starting points. These are
not literal templates — read them, then write the project's actual files
with the inspection results substituted and the irrelevant scaffolding
deleted.
Required substitutions in justfile.tmpl:
| Placeholder |
Value |
{{PROJECT_TITLE}} |
Human-readable project name (e.g., Facet). |
{{PROJECT_SLUG}} |
Normalized slug (lowercase, underscores). |
{{INSTALL_CMD}} |
From the language recipe block. |
{{DEV_CMD}} |
From the language recipe block. |
{{BUILD_CMD}} |
From the language recipe block. |
{{TYPECHECK_CMD}} |
From the language recipe block. |
{{LINT_CMD}} |
From the language recipe block (omit if not configured). |
{{TEST_CMD}} |
From the language recipe block. |
{{TEST_FILE_CMD}} |
From the language recipe block. |
{{TEST_WATCH_CMD}} |
From the language recipe block. |
{{CLEAN_CMD}} |
Project-specific build artifacts. |
In Makefile.tmpl, also keep the .PHONY list and the passthrough
recipe block in sync with the recipes actually emitted in the justfile —
the catch-all rule pattern is intentionally NOT used; an explicit list
keeps make help honest.
For each service, copy tx-start.sh.tmpl to
scripts/tx-start-<role>.sh, uncomment the relevant runtime activation
block, and replace {{SERVICE_CMD}} with the actual launch command.
Make the script executable: chmod +x scripts/tx-start-<role>.sh.
Step 5 — Validate
After writing the files, run these checks before declaring completion:
just --list — must succeed and show every recipe.
make help — must show the passthrough list.
- For each
svc-<role> recipe: confirm a matching tx-start-<role>.sh
exists, is executable, and has the right activation block uncommented.
just ci — should be runnable end-to-end (don't actually run it
unless the user wants to; just confirm the deps resolve).
- Confirm
set shell := ["zsh", "-c"] is present and that no recipe
uses bash-specific syntax that would break under zsh.
If any check fails, fix it before reporting done.
Style rules (non-negotiable)
These rules apply to every justfile produced by this skill:
- Header: comment block with project name, install hint, usage hint.
- Settings:
set dotenv-load := false and set shell := ["zsh", "-c"].
- Project identity: a
project justfile variable holding the
normalized slug, used to derive svc_session (via env("TMUX_SESSION", project)) and every tmux_<role>_window variable. Do NOT hardcode the
session name as a string literal — go through project so renaming the
project means changing one line.
- Default recipe:
default: @just --list.
- DRY service recipes: every
svc-<role> delegates to _svc-start;
every svc-stop-<role> delegates to _svc-stop. Do not inline the
tmux logic into individual service recipes.
- Standard targets:
install, dev, build, typecheck, lint,
test, test-file, test-watch, ci, clean — emit every one that
the project's tooling supports; omit the rest with no placeholder.
ci recipe: composes the static-check recipes — at minimum
typecheck, lint, test (add fmt-check for Rust/Go projects).
- Comments: one short line per recipe explaining intent. Skip if the
recipe name is self-explanatory (e.g.,
clean:).
Style rules for the Makefile
SHELL := /bin/bash and JUST_DEST ?= $(HOME)/bin.
default: help showing every passthrough target.
- Single block listing every passthrough recipe;
read -p prompt to
install just on first use.
test-file (and any other arg-bearing recipe) gets its own block that
forwards FILE=... as a positional just arg.
install-just cascade: brew → cargo → snap → official curl script,
with JUST_DEST PATH advice if falling back to the script.
Style rules for tx-start scripts
#!/usr/bin/env bash and set -euo pipefail.
- Resolve
ROOT_DIR from ${BASH_SOURCE[0]} so the script works from
any cwd.
- Activate the runtime if the project requires a specific version
(otherwise leave the block commented and let the inherited shell win).
- Set env defaults via
${VAR:-default} so the parent shell or .env
always wins.
- End with
exec <command> (not just <command>) so the wrapper PID
becomes the service PID.
Anti-patterns to avoid
- Using
bash as the just shell. The project standard is zsh; use
set shell := ["zsh", "-c"].
- Hardcoding the tmux session name as a string. Go through
project.
- Inlining the tmux logic in every
svc-* recipe. Use the _svc-start
helper instead.
- Calling
tmux capture-pane, tmux kill-window, etc. directly. Always
go through cortex tmux.
- Putting nvm/asdf activation in the justfile. That belongs in the
tx-start-*.sh wrapper.
- Adding a
lint recipe when the project has no linter configured. Omit
the recipe entirely; do not emit one that will fail.
- Using
&& chains where dependent recipes would be clearer (e.g.,
ci: typecheck lint test, not ci: && just typecheck && just lint && just test).
- Catch-all
%: rules in the Makefile. Keep the passthrough list
explicit so make help stays an honest reference.
Resources
assets/justfile.tmpl — canonical justfile structure with svc-* family.
assets/Makefile.tmpl — passthrough wrapper with install-just cascade.
assets/tx-start.sh.tmpl — service launch script pattern.
references/inspection-checklist.md — slug rules, stack detection,
service catalog detection.
references/recipes-node.md — pnpm/npm/yarn/bun command map.
references/recipes-rust.md — cargo recipes.
references/recipes-python.md — uv/poetry/pip recipes.
references/recipes-go.md — go recipes.
references/service-patterns.md — svc-* family, cortex tmux CLI,
internal helper pattern.
1---
2name: justfile-author
3description: Use this skill when authoring or refactoring a justfile (and matching Makefile wrapper) for one of Nick's projects. Triggers when the user asks to "create a justfile", "add a justfile to this project", "set up just for…", "wire up tmux services", "scaffold the task runner", or when working in a repo that lacks a justfile but obviously needs one. Produces a justfile using zsh syntax with the standard svc-* tmux service family, the canonical build/lint/dev/test recipes, a thin Makefile passthrough wrapper that auto-installs just, and per-service tx-start.sh helpers. Do NOT use for editing existing third-party justfiles or non-Nick projects unless the user explicitly opts in.
4keywords:
5 - justfile
6 - create a justfile
7 - add a justfile
8 - task runner
9 - tmux services
10 - Makefile wrapper
11 - svc-up
12---
13
14# Justfile Author
15
16## Overview
17
18Generate a justfile (and matching Makefile + tx-start helpers) following Nick's
19project conventions: zsh shell, DRY parameterized helpers, svc-* tmux service
20family wired through `cortex tmux`, and standard quality recipes
21(`build`, `lint`, `dev`, `test`, `typecheck`, `ci`, `clean`).
22
23## When to use this skill
24
25- A repo lacks a justfile and the user wants one.
26- A justfile exists but is missing the svc-* family, the Makefile wrapper,
27 or the standard quality recipes.
28- The user asks to add a new service window (e.g., `svc-worker`) to an
29 existing justfile.
30- The user asks to refactor a justfile to be more DRY or to align with
31 the conventions captured here.
32
33Skip this skill when:
34
35- Editing third-party / open-source justfiles (their conventions own).
36- The user has explicitly chosen `make`, `npm scripts`, or another runner
37 for this project.
38
39## Reference example
40
41`/Users/nick/Developer/Facet/justfile` and `/Users/nick/Developer/Facet/Makefile`
42are the canonical reference. When in doubt, mirror their shape.
43
44## Workflow
45
46### Step 1 — Inspect the project
47
48Before writing anything, read the project to determine:
49
501. **Project slug** — derive from the repo directory basename.
512. **Stack and package manager** — what language(s), which lockfile.
523. **Service catalog** — what long-running processes the dev runs locally.
534. **Existing tooling** — what build/test/lint commands the project
54 already uses (do not invent new ones).
555. **Runtime activation needs** — nvm, asdf, uv, etc.
56
57Consult `references/inspection-checklist.md` for the full detection table
58and the exact slug-normalization rules.
59
60### Step 2 — Choose the recipe block
61
62Pull the right language reference into context:
63
64| Stack | Reference |
65| ------ | ----------------------------- |
66| Node | `references/recipes-node.md` |
67| Rust | `references/recipes-rust.md` |
68| Python | `references/recipes-python.md`|
69| Go | `references/recipes-go.md` |
70
71For polyglot repos, read multiple references and combine. For stacks not
72listed, mirror the structure of the closest listed stack and substitute
73the native commands.
74
75### Step 3 — Choose the service catalog
76
77Consult `references/service-patterns.md` for the full svc-* surface area
78and the rules for when to add a new service window. Every detected
79service gets a parallel pair of recipes (foreground + svc-) and a
80`tx-start-<role>.sh` wrapper.
81
82### Step 4 — Emit the files
83
84Use `assets/justfile.tmpl`, `assets/Makefile.tmpl`, and
85`assets/tx-start.sh.tmpl` as the structural starting points. These are
86not literal templates — read them, then write the project's actual files
87with the inspection results substituted and the irrelevant scaffolding
88deleted.
89
90Required substitutions in `justfile.tmpl`:
91
92| Placeholder | Value |
93| ------------------- | ------------------------------------------------------ |
94| `{{PROJECT_TITLE}}` | Human-readable project name (e.g., `Facet`). |
95| `{{PROJECT_SLUG}}` | Normalized slug (lowercase, underscores). |
96| `{{INSTALL_CMD}}` | From the language recipe block. |
97| `{{DEV_CMD}}` | From the language recipe block. |
98| `{{BUILD_CMD}}` | From the language recipe block. |
99| `{{TYPECHECK_CMD}}` | From the language recipe block. |
100| `{{LINT_CMD}}` | From the language recipe block (omit if not configured).|
101| `{{TEST_CMD}}` | From the language recipe block. |
102| `{{TEST_FILE_CMD}}` | From the language recipe block. |
103| `{{TEST_WATCH_CMD}}`| From the language recipe block. |
104| `{{CLEAN_CMD}}` | Project-specific build artifacts. |
105
106In `Makefile.tmpl`, also keep the `.PHONY` list and the passthrough
107recipe block in sync with the recipes actually emitted in the justfile —
108the catch-all rule pattern is intentionally NOT used; an explicit list
109keeps `make help` honest.
110
111For each service, copy `tx-start.sh.tmpl` to
112`scripts/tx-start-<role>.sh`, uncomment the relevant runtime activation
113block, and replace `{{SERVICE_CMD}}` with the actual launch command.
114Make the script executable: `chmod +x scripts/tx-start-<role>.sh`.
115
116### Step 5 — Validate
117
118After writing the files, run these checks before declaring completion:
119
1201. `just --list` — must succeed and show every recipe.
1212. `make help` — must show the passthrough list.
1223. For each `svc-<role>` recipe: confirm a matching `tx-start-<role>.sh`
123 exists, is executable, and has the right activation block uncommented.
1244. `just ci` — should be runnable end-to-end (don't actually run it
125 unless the user wants to; just confirm the deps resolve).
1265. Confirm `set shell := ["zsh", "-c"]` is present and that no recipe
127 uses bash-specific syntax that would break under zsh.
128
129If any check fails, fix it before reporting done.
130
131## Style rules (non-negotiable)
132
133These rules apply to every justfile produced by this skill:
134
135- **Header**: comment block with project name, install hint, usage hint.
136- **Settings**: `set dotenv-load := false` and `set shell := ["zsh", "-c"]`.
137- **Project identity**: a `project` justfile variable holding the
138 normalized slug, used to derive `svc_session` (via `env("TMUX_SESSION",
139 project)`) and every `tmux_<role>_window` variable. Do NOT hardcode the
140 session name as a string literal — go through `project` so renaming the
141 project means changing one line.
142- **Default recipe**: `default: @just --list`.
143- **DRY service recipes**: every `svc-<role>` delegates to `_svc-start`;
144 every `svc-stop-<role>` delegates to `_svc-stop`. Do not inline the
145 tmux logic into individual service recipes.
146- **Standard targets**: `install`, `dev`, `build`, `typecheck`, `lint`,
147 `test`, `test-file`, `test-watch`, `ci`, `clean` — emit every one that
148 the project's tooling supports; omit the rest with no placeholder.
149- **`ci` recipe**: composes the static-check recipes — at minimum
150 `typecheck`, `lint`, `test` (add `fmt-check` for Rust/Go projects).
151- **Comments**: one short line per recipe explaining intent. Skip if the
152 recipe name is self-explanatory (e.g., `clean:`).
153
154## Style rules for the Makefile
155
156- `SHELL := /bin/bash` and `JUST_DEST ?= $(HOME)/bin`.
157- `default: help` showing every passthrough target.
158- Single block listing every passthrough recipe; `read -p` prompt to
159 install just on first use.
160- `test-file` (and any other arg-bearing recipe) gets its own block that
161 forwards `FILE=...` as a positional just arg.
162- `install-just` cascade: brew → cargo → snap → official curl script,
163 with `JUST_DEST` PATH advice if falling back to the script.
164
165## Style rules for tx-start scripts
166
167- `#!/usr/bin/env bash` and `set -euo pipefail`.
168- Resolve `ROOT_DIR` from `${BASH_SOURCE[0]}` so the script works from
169 any cwd.
170- Activate the runtime if the project requires a specific version
171 (otherwise leave the block commented and let the inherited shell win).
172- Set env defaults via `${VAR:-default}` so the parent shell or `.env`
173 always wins.
174- End with `exec <command>` (not just `<command>`) so the wrapper PID
175 becomes the service PID.
176
177## Anti-patterns to avoid
178
179- Using `bash` as the just shell. The project standard is zsh; use
180 `set shell := ["zsh", "-c"]`.
181- Hardcoding the tmux session name as a string. Go through `project`.
182- Inlining the tmux logic in every `svc-*` recipe. Use the `_svc-start`
183 helper instead.
184- Calling `tmux capture-pane`, `tmux kill-window`, etc. directly. Always
185 go through `cortex tmux`.
186- Putting nvm/asdf activation in the justfile. That belongs in the
187 `tx-start-*.sh` wrapper.
188- Adding a `lint` recipe when the project has no linter configured. Omit
189 the recipe entirely; do not emit one that will fail.
190- Using `&&` chains where dependent recipes would be clearer (e.g.,
191 `ci: typecheck lint test`, not `ci: && just typecheck && just lint && just test`).
192- Catch-all `%:` rules in the Makefile. Keep the passthrough list
193 explicit so `make help` stays an honest reference.
194
195## Resources
196
197- `assets/justfile.tmpl` — canonical justfile structure with svc-* family.
198- `assets/Makefile.tmpl` — passthrough wrapper with install-just cascade.
199- `assets/tx-start.sh.tmpl` — service launch script pattern.
200- `references/inspection-checklist.md` — slug rules, stack detection,
201 service catalog detection.
202- `references/recipes-node.md` — pnpm/npm/yarn/bun command map.
203- `references/recipes-rust.md` — cargo recipes.
204- `references/recipes-python.md` — uv/poetry/pip recipes.
205- `references/recipes-go.md` — go recipes.
206- `references/service-patterns.md` — svc-* family, cortex tmux CLI,
207 internal helper pattern.