Skip to content

Commit 843ba1c

Browse files
baonguyenNavaclaude
andcommitted
Add remaining scripts and sync docs for rails-app refactor
Completes the script-driven refactor: adds the three scripts the refactored SKILL.md depends on (preflight, install-app, verify-app) alongside the already-committed add-strata-sdk.sh. Also syncs documentation: - CLAUDE.md: document bundled scripts/ + references/ and marker convention - README.md: update rails-app row, add missing model-workflow row - references/strata-sdk.md: add canonical Gemfile install snippet Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
1 parent 4e3056a commit 843ba1c

6 files changed

Lines changed: 186 additions & 1 deletion

File tree

CLAUDE.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,10 @@ python -m pytest tests/test_lint_skills.py -v -k "test_name_here"
1919

2020
Each skill lives in `skills/<skill-name>/SKILL.md`. The linter (`scripts/lint_skills.py`) validates all skills against 12 rules on every CI run.
2121

22+
A skill may bundle supporting files alongside its `SKILL.md`:
23+
- `references/` — shared markdown the skill reads before acting (e.g. `ruby-version-check.md`).
24+
- `scripts/` — shell scripts the skill invokes to collapse multi-command sequences into a single turn. Scripts print labeled status lines ending in a marker (e.g. `PREFLIGHT_OK`, `NEEDS_DOCKER`, `INSTALL_OK`, `VERIFY_FAILED <target>`) and use distinct exit codes; the SKILL.md instructs the model to read the marker and branch. SKILL.md references scripts by `<SKILL_DIR>/scripts/...` (absolute) so they resolve regardless of the working directory. The linter only validates `SKILL.md`, not these bundled files.
25+
2226
**SKILL.md format:**
2327
```markdown
2428
---

README.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,8 +48,9 @@ npx skills update
4848

4949
| Skill | Description |
5050
|-------|-------------|
51-
| `build-strata-rails-app` | Scaffolds a new Nava Strata application using nava-platform CLI and the navapbc/template-application-rails template |
51+
| `build-strata-rails-app` | Scaffolds a new Nava Strata application using nava-platform CLI and the navapbc/template-application-rails template, then optionally installs the Strata SDK. Delegates command sequences to bundled `scripts/` to reduce turns |
5252
| `build-strata-sdk-model` | Adds a single Rails model to an existing Rails app — plain ActiveRecord, or a Strata SDK variant (application form, case, business process) |
53+
| `build-strata-sdk-model-workflow` | Multi-agent Workflow orchestrator variant — proposes, audits, and verifies model attributes across two human checkpoints before test-first implementation |
5354
| `build-strata-app-form-views` | Builds views, flow, and routes for a Strata multi-page application form on top of an existing ApplicationForm model |
5455

5556
## Learn more

references/strata-sdk.md

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,20 @@ Authoritative knowledge of the Strata SDK Rails engine: docs, generators, models
44

55
The SDK lives at `https://github.com/navapbc/strata-sdk-rails` and is installed as a gem via Bundler. Run `bundle show strata` to find the local install path (`<SDK_GEM_PATH>`). The repo is also called `flex-sdk` upstream — both URLs resolve.
66

7+
## 0. Installation
8+
9+
Add these lines to the app's `Gemfile`, then `bundle install`:
10+
11+
```ruby
12+
# Strata Government Digital Services SDK Rails engine
13+
gem "strata", git: "https://github.com/navapbc/strata-sdk-rails.git"
14+
15+
# Strata gem only requires validates_timeliness version 7 for Rails 7 which is the minimum Strata Rails version.
16+
gem "validates_timeliness", "~> 8.0"
17+
```
18+
19+
The `build-strata-rails-app` skill offers to do this automatically at the end of scaffolding (`scripts/add-strata-sdk.sh`), which also re-runs lint + test.
20+
721
## 1. Docs catalog
822

923
```sh
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
#!/usr/bin/env sh
2+
#
3+
# install-app.sh <APP_NAME> — validate the name, guard against an existing
4+
# directory, and apply the Rails application template.
5+
# Folds the old "check existing dir" and "apply template" steps.
6+
#
7+
# Markers the skill watches for:
8+
# INVALID_NAME — name does not match ^[a-z0-9_-]+$
9+
# DIR_EXISTS — a directory named <APP_NAME>/ already exists
10+
# INSTALL_OK <name> — template applied successfully
11+
12+
set -u
13+
14+
APP_NAME="${1:-}"
15+
16+
if [ -z "$APP_NAME" ]; then
17+
echo "INVALID_NAME: no app name provided (usage: install-app.sh <APP_NAME>)"
18+
exit 1
19+
fi
20+
21+
# 1. Validate name -----------------------------------------------------------
22+
case "$APP_NAME" in
23+
*[!a-z0-9_-]*)
24+
echo "INVALID_NAME: '$APP_NAME' — use lowercase letters, digits, dashes, underscores only."
25+
exit 1
26+
;;
27+
esac
28+
29+
# 2. Existing-directory guard ------------------------------------------------
30+
# Trailing slash forces directory resolution; ls exits non-zero if absent.
31+
if ls -ld -- "$APP_NAME/" >/dev/null 2>&1; then
32+
echo "DIR_EXISTS: a directory named '$APP_NAME/' already exists — rename or remove it first."
33+
exit 1
34+
fi
35+
36+
# 3. Apply the template ------------------------------------------------------
37+
echo "INSTALL: applying Rails template into ./$APP_NAME"
38+
if nava-platform app install \
39+
--template-uri https://github.com/navapbc/template-application-rails \
40+
--data app_local_port=3000 \
41+
. "$APP_NAME"; then
42+
echo "INSTALL_OK $APP_NAME"
43+
exit 0
44+
else
45+
echo "INSTALL_FAILED: nava-platform app install failed — see output above."
46+
exit 1
47+
fi
Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
#!/usr/bin/env sh
2+
#
3+
# preflight.sh — environment checks for scaffolding a Strata Rails app.
4+
# Folds the old "check/install CLI" and "check Docker / Postgres port / git" steps.
5+
#
6+
# Prints labeled status lines. On a condition the user must resolve, prints a
7+
# NEEDS_* marker and exits non-zero so the calling skill can stop and ask.
8+
# On full success prints PREFLIGHT_OK and exits 0.
9+
#
10+
# Markers the skill watches for:
11+
# NEEDS_UV — nava-platform CLI missing and uv not installed
12+
# NEEDS_DOCKER — Docker daemon not running
13+
# NEEDS_PORT_FREE — port 5432 held by a process we won't auto-stop
14+
# PREFLIGHT_OK — all checks passed
15+
16+
set -u
17+
18+
# 1. nava-platform CLI -------------------------------------------------------
19+
if nava-platform --help >/dev/null 2>&1; then
20+
echo "CLI: nava-platform already installed"
21+
else
22+
echo "CLI: nava-platform not found — attempting install via uv"
23+
if uv --version >/dev/null 2>&1; then
24+
if uv tool install git+https://github.com/navapbc/platform-cli; then
25+
if nava-platform --help >/dev/null 2>&1; then
26+
echo "CLI: nava-platform installed"
27+
else
28+
echo "NEEDS_UV: installed via uv but nava-platform still not on PATH (restart shell / check ~/.local/bin)"
29+
exit 1
30+
fi
31+
else
32+
echo "NEEDS_UV: 'uv tool install' failed — see output above"
33+
exit 1
34+
fi
35+
else
36+
echo "NEEDS_UV: uv is not installed. Install it (https://docs.astral.sh/uv/getting-started/installation/) then re-run."
37+
exit 1
38+
fi
39+
fi
40+
41+
# 2. Docker daemon -----------------------------------------------------------
42+
if docker ps >/dev/null 2>&1; then
43+
echo "DOCKER: daemon running"
44+
else
45+
echo "NEEDS_DOCKER: Docker daemon not running — start Docker Desktop then re-run."
46+
exit 1
47+
fi
48+
49+
# 3. Postgres port 5432 ------------------------------------------------------
50+
PG_PIDS=$(lsof -iTCP:5432 -sTCP:LISTEN -t 2>/dev/null || true)
51+
if [ -z "$PG_PIDS" ]; then
52+
echo "PORT: 5432 free"
53+
else
54+
PG_CMD=$(lsof -iTCP:5432 -sTCP:LISTEN 2>/dev/null | awk 'NR==2 {print $1}')
55+
case "$PG_CMD" in
56+
com.docke* | docker | docker-proxy)
57+
echo "PORT: 5432 held by Docker ($PG_CMD) — stopping the container"
58+
CONTAINER=$(docker ps --filter "publish=5432" -q)
59+
if [ -n "$CONTAINER" ]; then
60+
docker stop $CONTAINER >/dev/null 2>&1
61+
fi
62+
# re-check
63+
if [ -n "$(lsof -iTCP:5432 -sTCP:LISTEN -t 2>/dev/null || true)" ]; then
64+
echo "NEEDS_PORT_FREE: docker container stopped but 5432 still busy"
65+
exit 1
66+
fi
67+
echo "PORT: 5432 freed"
68+
;;
69+
postgres)
70+
echo "NEEDS_PORT_FREE: native postgres on 5432 — do NOT auto-stop. Ask user to stop it (e.g. 'brew services stop postgresql@16') then re-run."
71+
exit 1
72+
;;
73+
*)
74+
echo "NEEDS_PORT_FREE: 5432 held by '${PG_CMD:-unknown}' — ask user to free the port then re-run."
75+
exit 1
76+
;;
77+
esac
78+
fi
79+
80+
# 4. git repository ----------------------------------------------------------
81+
if git rev-parse --is-inside-work-tree >/dev/null 2>&1; then
82+
echo "GIT: already inside a git repo"
83+
else
84+
echo "GIT: not a repo — running git init"
85+
git init >/dev/null
86+
echo "GIT: initialized"
87+
fi
88+
89+
echo "PREFLIGHT_OK"
90+
exit 0
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
#!/usr/bin/env sh
2+
#
3+
# verify-app.sh — prepare and verify the generated app.
4+
# Run from INSIDE the <APP_NAME>/ directory.
5+
# Folds the old "run make targets in order" step.
6+
#
7+
# Runs each make target in order, stops on the first failure.
8+
#
9+
# Markers the skill watches for:
10+
# VERIFY_FAILED <target> — the named make target failed
11+
# VERIFY_OK — all targets passed
12+
13+
set -u
14+
15+
if [ ! -f Makefile ]; then
16+
echo "VERIFY_FAILED: no Makefile in $(pwd) — are you inside the app directory?"
17+
exit 1
18+
fi
19+
20+
for target in ".env" "init-db" "build" "precompile-assets" "lint" "test"; do
21+
echo "=== make $target ==="
22+
if ! make "$target"; then
23+
echo "VERIFY_FAILED: $target"
24+
exit 1
25+
fi
26+
done
27+
28+
echo "VERIFY_OK"
29+
exit 0

0 commit comments

Comments
 (0)