diff --git a/.cursor/environment.json b/.cursor/environment.json new file mode 100644 index 0000000..b6971df --- /dev/null +++ b/.cursor/environment.json @@ -0,0 +1,3 @@ +{ + "install": "sh scripts/install-cursor-cloud-skills.sh" +} diff --git a/.cursor/skills/fstack b/.cursor/skills/fstack new file mode 120000 index 0000000..ed0136c --- /dev/null +++ b/.cursor/skills/fstack @@ -0,0 +1 @@ +../../skills/fstack \ No newline at end of file diff --git a/.cursor/skills/fstack-build b/.cursor/skills/fstack-build new file mode 120000 index 0000000..5c945a1 --- /dev/null +++ b/.cursor/skills/fstack-build @@ -0,0 +1 @@ +../../skills/fstack-build \ No newline at end of file diff --git a/.cursor/skills/fstack-check b/.cursor/skills/fstack-check new file mode 120000 index 0000000..a89815c --- /dev/null +++ b/.cursor/skills/fstack-check @@ -0,0 +1 @@ +../../skills/fstack-check \ No newline at end of file diff --git a/.cursor/skills/fstack-counselors b/.cursor/skills/fstack-counselors new file mode 120000 index 0000000..01ef37c --- /dev/null +++ b/.cursor/skills/fstack-counselors @@ -0,0 +1 @@ +../../skills/fstack-counselors \ No newline at end of file diff --git a/.cursor/skills/fstack-design b/.cursor/skills/fstack-design new file mode 120000 index 0000000..7c7953d --- /dev/null +++ b/.cursor/skills/fstack-design @@ -0,0 +1 @@ +../../skills/fstack-design \ No newline at end of file diff --git a/.cursor/skills/fstack-document b/.cursor/skills/fstack-document new file mode 120000 index 0000000..eed65b0 --- /dev/null +++ b/.cursor/skills/fstack-document @@ -0,0 +1 @@ +../../skills/fstack-document \ No newline at end of file diff --git a/.cursor/skills/fstack-interview b/.cursor/skills/fstack-interview new file mode 120000 index 0000000..3f77236 --- /dev/null +++ b/.cursor/skills/fstack-interview @@ -0,0 +1 @@ +../../skills/fstack-interview \ No newline at end of file diff --git a/.cursor/skills/fstack-learn b/.cursor/skills/fstack-learn new file mode 120000 index 0000000..0721fc7 --- /dev/null +++ b/.cursor/skills/fstack-learn @@ -0,0 +1 @@ +../../skills/fstack-learn \ No newline at end of file diff --git a/.cursor/skills/fstack-nail b/.cursor/skills/fstack-nail new file mode 120000 index 0000000..99c7da2 --- /dev/null +++ b/.cursor/skills/fstack-nail @@ -0,0 +1 @@ +../../skills/fstack-nail \ No newline at end of file diff --git a/.cursor/skills/fstack-plan b/.cursor/skills/fstack-plan new file mode 120000 index 0000000..f5d3fdc --- /dev/null +++ b/.cursor/skills/fstack-plan @@ -0,0 +1 @@ +../../skills/fstack-plan \ No newline at end of file diff --git a/.cursor/skills/fstack-push b/.cursor/skills/fstack-push new file mode 120000 index 0000000..e5d1119 --- /dev/null +++ b/.cursor/skills/fstack-push @@ -0,0 +1 @@ +../../skills/fstack-push \ No newline at end of file diff --git a/.cursor/skills/fstack-roast b/.cursor/skills/fstack-roast new file mode 120000 index 0000000..9c92b5f --- /dev/null +++ b/.cursor/skills/fstack-roast @@ -0,0 +1 @@ +../../skills/fstack-roast \ No newline at end of file diff --git a/.cursor/skills/fstack-run b/.cursor/skills/fstack-run new file mode 120000 index 0000000..b1343cb --- /dev/null +++ b/.cursor/skills/fstack-run @@ -0,0 +1 @@ +../../skills/fstack-run \ No newline at end of file diff --git a/.cursor/skills/fstack-simplify b/.cursor/skills/fstack-simplify new file mode 120000 index 0000000..94f84c3 --- /dev/null +++ b/.cursor/skills/fstack-simplify @@ -0,0 +1 @@ +../../skills/fstack-simplify \ No newline at end of file diff --git a/AGENTS.md b/AGENTS.md index cdad7bb..bea90ca 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -43,6 +43,7 @@ Run all applicable checks. For this repository, the minimum gate is: ```sh sh -n scripts/validate.sh sh -n scripts/test-validate.sh +sh -n scripts/install-cursor-cloud-skills.sh sh scripts/test-validate.sh sh scripts/validate.sh git diff --check diff --git a/README.md b/README.md index d7b0191..5a0a46a 100644 --- a/README.md +++ b/README.md @@ -114,6 +114,9 @@ This fork includes: - `.github/copilot-instructions.md` — GitHub Copilot coding-agent entrypoint; - `.github/workflows/validate.yml` — automatic skill validation; - `.github/pull_request_template.md` — evidence-focused delivery checklist; +- `.cursor/environment.json` — Cursor cloud install hook that runs on each environment boot; +- `.cursor/skills/` — Cursor project skill discovery via symlinks to `skills/`; +- `scripts/install-cursor-cloud-skills.sh` — copies skills into `~/.cursor/skills` for cloud session persistence; - `scripts/validate.sh` — dependency-free frontmatter, naming, size, duplication, and README checks; - `scripts/test-validate.sh` — regression tests for validator behavior and path safety; - `docs/CLOUD_AGENTS.md` — complete operator guide. @@ -123,6 +126,7 @@ Validate locally with: ```sh sh -n scripts/validate.sh sh -n scripts/test-validate.sh +sh -n scripts/install-cursor-cloud-skills.sh sh scripts/test-validate.sh sh scripts/validate.sh git diff --check diff --git a/docs/CLOUD_AGENTS.md b/docs/CLOUD_AGENTS.md index 1af7791..5da8469 100644 --- a/docs/CLOUD_AGENTS.md +++ b/docs/CLOUD_AGENTS.md @@ -4,7 +4,28 @@ The original skills remain interactive. Use them when you want to drive each stage manually. -## 1. Review before installing +## 1. Cursor Cloud Agents + +Cursor Cloud Agents do not sync laptop-global `~/.cursor/skills`. This repository installs skills for cloud sessions in two ways: + +1. **Project discovery:** `.cursor/skills/` symlinks to the canonical `skills/` trees so agents pick skills up from the checkout. +2. **Session home install:** `.cursor/environment.json` runs `scripts/install-cursor-cloud-skills.sh`, which copies every skill into `~/.cursor/skills` on the cloud VM. That install is idempotent and re-runs on each environment boot. + +To refresh the home install in an already-running cloud session: + +```sh +sh scripts/install-cursor-cloud-skills.sh +``` + +Override the destination when testing: + +```sh +CURSOR_CLOUD_SKILLS_HOME=/tmp/cursor-skills-home sh scripts/install-cursor-cloud-skills.sh +``` + +After merging, start a new cloud agent on this repository so `.cursor/environment.json` is applied. Optionally save a cloud environment snapshot from the [Cloud Agents dashboard](https://cursor.com/dashboard/cloud-agents#environments) so later sessions reuse the installed home skills faster. + +## 2. Review before installing Agent skills are executable instructions. Inspect this repository and the selected `SKILL.md` before giving an agent write access to an important repository. @@ -20,7 +41,7 @@ For clients using the cross-agent `skills` CLI, list the collection without inst npx skills@latest add naytewilson/fstack --list ``` -## 2. Install with GitHub CLI +## 3. Install with GitHub CLI `gh skill` is GitHub's preview interface for Copilot cloud agent and supported agent hosts. A project install is the safest default because the reviewed skill version travels with one repository. @@ -44,7 +65,7 @@ gh skill install naytewilson/fstack fstack-run --pin The installer writes the skill into the correct host-specific location. GitHub Copilot project skills live under `.github/skills`, `.claude/skills`, or `.agents/skills`; personal skills live under `~/.copilot/skills` or `~/.agents/skills`. -## 3. Install with the cross-agent CLI +## 4. Install with the cross-agent CLI Use this route for Codex, Claude Code, OpenCode, and other clients supported by the `skills` CLI. @@ -74,7 +95,7 @@ npx skills@latest add naytewilson/fstack --all Project installation is better when a team should share the same version. Global installation is better for a personal default across repositories. -## 4. Give the cloud agent the right repository access +## 5. Give the cloud agent the right repository access A full run needs: @@ -86,7 +107,7 @@ A full run needs: It does not need permission to force-push, merge, deploy, edit repository settings, or read production secrets for ordinary coding tasks. Keep those permissions disabled unless a specific task requires them. -## 5. Start a run +## 6. Start a run A compact task is enough: @@ -96,7 +117,7 @@ Use /fstack-run. Fix the reported issue end to end. Inspect source truth first, Include acceptance criteria, issue links, screenshots, or failing commands when they exist. Do not restate repository facts that the agent can inspect. -## 6. Expected lifecycle +## 7. Expected lifecycle A compliant cloud run performs this loop: @@ -106,18 +127,20 @@ inspect -> isolate -> plan briefly -> implement -> test -> review -> fix -> rete The agent may repeat implementation, testing, and review. It should not stop merely because one phase completed. -## 7. Repository instruction files +## 8. Repository instruction files This repository includes: - `AGENTS.md` as the canonical cross-agent contract; - `CLAUDE.md` as a Claude Code entrypoint; - `.github/copilot-instructions.md` as a GitHub Copilot coding-agent entrypoint; +- `.cursor/environment.json` and `scripts/install-cursor-cloud-skills.sh` for Cursor cloud skill persistence; +- `.cursor/skills/` symlinks for Cursor project skill discovery; - `skills/fstack-run/SKILL.md` as the portable continuous workflow. When installing fstack into another repository, that repository's own instructions remain authoritative. The skill must adapt to them rather than overwrite them. -## 8. Verification and delivery +## 9. Verification and delivery A successful run must provide observed evidence for: @@ -137,6 +160,7 @@ For this skills repository, run: ```sh sh -n scripts/validate.sh sh -n scripts/test-validate.sh +sh -n scripts/install-cursor-cloud-skills.sh sh scripts/test-validate.sh sh scripts/validate.sh git diff --check @@ -150,7 +174,7 @@ gh skill publish --dry-run The publish dry run validates the skills and reports relevant repository security settings without creating a release. -## 9. Safe automation defaults +## 10. Safe automation defaults Use these defaults for unattended cloud execution: @@ -165,7 +189,7 @@ Use these defaults for unattended cloud execution: Do not add `allowed-tools: shell` or `allowed-tools: bash` merely to suppress prompts. Pre-approve terminal execution only after auditing the full skill and every referenced script. -## 10. Repository settings worth enabling +## 11. Repository settings worth enabling For repositories where cloud agents routinely open pull requests, enable: @@ -179,7 +203,7 @@ For repositories where cloud agents routinely open pull requests, enable: These are host-level controls. Installing a skill does not configure them automatically. -## 11. Update and audit +## 12. Update and audit Review upstream changes before updating a trusted automation environment. @@ -199,7 +223,7 @@ npx skills update Pinned GitHub CLI installations are skipped by normal updates. Reinstall them with a newly reviewed pin when you deliberately upgrade. -## 12. Troubleshooting +## 13. Troubleshooting ### The agent stops after planning @@ -216,3 +240,5 @@ The run is incomplete. Resume it with the missing verification requirement and r ### The client cannot find the skill Preview or list the repository, verify the selected agent and installation scope, and confirm that the installed folder contains `fstack-run/SKILL.md` with intact YAML frontmatter. + +For Cursor Cloud Agents, confirm `.cursor/skills/fstack-run/SKILL.md` resolves from the checkout and that `sh scripts/install-cursor-cloud-skills.sh` populated `~/.cursor/skills`. New sessions need `.cursor/environment.json` from the branch they check out. diff --git a/scripts/install-cursor-cloud-skills.sh b/scripts/install-cursor-cloud-skills.sh new file mode 100755 index 0000000..a3371d6 --- /dev/null +++ b/scripts/install-cursor-cloud-skills.sh @@ -0,0 +1,40 @@ +#!/bin/sh +# Install fstack skills into the Cursor Cloud Agent home path so they persist +# across cloud sessions that reuse this environment. +# +# Idempotent: safe to re-run from .cursor/environment.json install. +# Canonical skills stay in skills/; this only copies into ~/.cursor/skills. + +set -eu + +root=$(CDPATH= cd -- "$(dirname "$0")/.." && pwd) +src="$root/skills" +dest="${CURSOR_CLOUD_SKILLS_HOME:-${HOME}/.cursor/skills}" + +if [ ! -d "$src" ]; then + printf '%s\n' "ERROR: missing skills directory: $src" >&2 + exit 1 +fi + +mkdir -p "$dest" + +installed=0 +for skill_dir in "$src"/*/; do + [ -d "$skill_dir" ] || continue + name=$(basename "$skill_dir") + if [ ! -f "$skill_dir/SKILL.md" ]; then + printf '%s\n' "skip $name (no SKILL.md)" + continue + fi + rm -rf "$dest/$name" + cp -R "$skill_dir" "$dest/$name" + installed=$((installed + 1)) + printf '%s\n' "installed $name -> $dest/$name" +done + +if [ "$installed" -eq 0 ]; then + printf '%s\n' 'ERROR: no skills installed.' >&2 + exit 1 +fi + +printf '%s\n' "Installed $installed Cursor cloud skill(s) into $dest." diff --git a/scripts/test-validate.sh b/scripts/test-validate.sh index b7d0705..a27f75b 100644 --- a/scripts/test-validate.sh +++ b/scripts/test-validate.sh @@ -34,6 +34,17 @@ name: fstack-run description: Continuous runner. --- MARKDOWN + + mkdir -p "$fixture/.cursor/skills" "$fixture/scripts" + cat > "$fixture/.cursor/environment.json" <<'JSON' +{ + "install": "sh scripts/install-cursor-cloud-skills.sh" +} +JSON + cp "$root/scripts/install-cursor-cloud-skills.sh" \ + "$fixture/scripts/install-cursor-cloud-skills.sh" + ln -sfn ../../skills/fstack "$fixture/.cursor/skills/fstack" + ln -sfn ../../skills/fstack-run "$fixture/.cursor/skills/fstack-run" } expect_failure() { @@ -67,4 +78,25 @@ cat > "$fixture/README.md" <<'MARKDOWN' MARKDOWN expect_failure 'README.md does not document /fstack-run.' +write_valid_fixture +rm -f "$fixture/.cursor/skills/fstack-run" +expect_failure '.cursor/skills/fstack-run does not resolve to SKILL.md.' + +write_valid_fixture +rm -f "$fixture/.cursor/environment.json" +expect_failure 'missing .cursor/environment.json for Cursor cloud skill install.' + +write_valid_fixture +install_dest="$tmp_root/cursor-skills-home" +CURSOR_CLOUD_SKILLS_HOME="$install_dest" \ + sh "$fixture/scripts/install-cursor-cloud-skills.sh" > "$tmp_root/install-out" +if [ ! -f "$install_dest/fstack/SKILL.md" ] || [ ! -f "$install_dest/fstack-run/SKILL.md" ]; then + printf 'ERROR: install-cursor-cloud-skills.sh did not copy skills.\n' >&2 + exit 1 +fi +if grep -Fq 'local-path:' "$install_dest/fstack-run/SKILL.md"; then + printf 'ERROR: install script must copy skills without installer metadata.\n' >&2 + exit 1 +fi + printf '%s\n' 'Validator tests passed.' diff --git a/scripts/validate.sh b/scripts/validate.sh index a687272..7d348a4 100644 --- a/scripts/validate.sh +++ b/scripts/validate.sh @@ -95,6 +95,45 @@ while IFS= read -r file; do fi done < "$files_file" +cursor_env="$root/.cursor/environment.json" +cursor_skills="$root/.cursor/skills" +install_script="$root/scripts/install-cursor-cloud-skills.sh" + +if [ ! -f "$cursor_env" ]; then + printf 'ERROR: missing .cursor/environment.json for Cursor cloud skill install.\n' >&2 + failures=$((failures + 1)) +elif ! grep -Fq 'scripts/install-cursor-cloud-skills.sh' "$cursor_env"; then + printf 'ERROR: .cursor/environment.json must run scripts/install-cursor-cloud-skills.sh.\n' >&2 + failures=$((failures + 1)) +fi + +if [ ! -f "$install_script" ]; then + printf 'ERROR: missing scripts/install-cursor-cloud-skills.sh.\n' >&2 + failures=$((failures + 1)) +fi + +if [ ! -d "$cursor_skills" ]; then + printf 'ERROR: missing .cursor/skills for Cursor project discovery.\n' >&2 + failures=$((failures + 1)) +else + while IFS= read -r name; do + [ -n "$name" ] || continue + if [ ! -e "$cursor_skills/$name/SKILL.md" ]; then + printf 'ERROR: .cursor/skills/%s does not resolve to SKILL.md.\n' "$name" >&2 + failures=$((failures + 1)) + fi + done < "$names_file" + + for entry in "$cursor_skills"/*; do + [ -e "$entry" ] || continue + name=$(basename "$entry") + if [ ! -f "$root/skills/$name/SKILL.md" ]; then + printf 'ERROR: .cursor/skills/%s has no matching skills/%s.\n' "$name" "$name" >&2 + failures=$((failures + 1)) + fi + done +fi + if [ "$failures" -ne 0 ]; then printf 'Validation failed: %s problem(s) across %s skill(s).\n' "$failures" "$count" >&2 exit 1