# After Hours

> Unattended overnight develop loop for this repo. Orchestrator-only agent launches worker subagents on a fixed interval, verifies with sail artisan test, commits and pushes to development, and writes a dated morning report. Use when the user runs /after-hours or asks to keep developing unattended.

- Skill: `dca23/after-hours` (Agent Skill)
- Install (CLI): `npx skillmds@latest add dca23/after-hours`
- Raw SKILL.md: https://api.skillmd.com/api/skills/dca23/after-hours/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: AI & ML
- Author: DCa23 (https://skillmd.com/u/dca23)
- Updated: 2026-09-22
- Page: https://skillmd.com/skills/dca23/after-hours

---


# After Hours

Orchestrate unattended development. **You never edit application code yourself.** Every implementation change is done by a worker subagent you launch.

## Usage

```text
/after-hours [goal] [--interval Nm] [--max N]
```

| Flag | Default | Meaning |
|------|---------|---------|
| goal | contents of `TODO.md` if present | Freeform objective for the night |
| `--interval` | `10m` | Fixed wake interval (`30s`, `5m`, `10m`, `1h`, …) |
| `--max` | `20` | Stop after this many loop ticks |

If no goal is given and `TODO.md` is missing or empty, stop and ask for a goal. Do not invent work.

## Laravel Sail (required)

This app runs in Docker via Laravel Sail. **Never** run host PHP / Composer / Artisan / npm against the project directly.

| Wrong | Right |
|-------|--------|
| `php artisan …` | `./vendor/bin/sail artisan …` |
| `php artisan test` | `./vendor/bin/sail artisan test` |
| `composer …` | `./vendor/bin/sail composer …` |
| `npm …` / `npx …` | `./vendor/bin/sail npm …` / `./vendor/bin/sail npx …` |
| `php …` | `./vendor/bin/sail php …` |

Prefer `./vendor/bin/sail` over a bare `sail` alias so workers work in any shell. If Sail containers are not up, start with `./vendor/bin/sail up -d` before tests; if that fails, treat the tick as failed.

Put this Sail rule in every worker subagent prompt.

## Unattended command execution

Workers must not pause for human approval of routine commands.

1. For every Sail / Docker / `git push` shell call, pass `required_permissions: ["all"]` on the **first** attempt (Sail needs Docker outside the sandbox).
2. Do not ask the user whether a command may run. Proceed; if Cursor still blocks, report the tick as failed with the exact blocker.
3. At startup, remind the user once: for a truly hands-off night, set **Settings → Agents → Approvals & Execution** to **Run Everything** (Auto-review + project `permissions.json` still helps, but Docker/Sail often prompts otherwise).
4. Project helpers already in place: `.cursor/permissions.json` (Auto-review allow lean) and `.cursor/hooks.json` (auto-allow Sail/git while `.after-hours/state.md` has `status: running`).

## Hard rules

1. **Orchestrator only** — no direct edits to app/tests/config/frontend source. Allowed local writes: `.after-hours/**`, `docs/after-hours/**`.
2. **Workers do the code** — launch `Task` with `subagent_type: "generalPurpose"` (or `shell` for git/test-only chores). One slice per worker.
3. **Branch** — all work lands on `development`. Create it from `main` if missing, then checkout and track `origin/development` when possible.
4. **Sail for all runtime commands** — workers and any shell chores use Sail only (see above). Verify with `./vendor/bin/sail artisan test` before reporting success.
5. **Ship by default** — after a successful worker slice with changes: commit and `git push -u origin development`. Never force-push, never `--no-verify`, never amend unless the user rules for amend are fully satisfied.
6. **Morning report** — always maintain `docs/after-hours/YYYY-MM-DD.md` where the date is the **loop start date** (local), regardless of commit/push outcome for a given tick.

## Startup (once)

1. Parse args (goal, interval, max).
2. Ensure on `development` (create/checkout as needed).
3. Create dirs: `.after-hours/`, `docs/after-hours/`.
4. Write `.after-hours/state.md`:

```markdown
---
started: YYYY-MM-DD
started_at: ISO-8601
interval: 10m
max_iterations: 20
iteration: 0
status: running
goal: |
  <goal text>
loop_pid:
---

# Plan
- [ ] <break goal into concrete slices>

# Log
```

5. Create or overwrite the morning report for tonight:

`docs/after-hours/YYYY-MM-DD.md` (date = `started` from state):

```markdown
# After Hours — YYYY-MM-DD

**Goal:** <goal>
**Branch:** development
**Started:** <ISO-8601>

## Summary

_Working…_

## Commits
```

6. Confirm briefly: goal, interval, max, branch, report path. Remind once to use **Run Everything** approvals for hands-off Sail/Docker.
7. Arm the fixed loop (below), then run **tick 1 immediately**.

## Fixed loop

Follow the Cursor **loop** skill fixed-schedule pattern.

1. Check terminals for an existing after-hours loop; do not duplicate.
2. Convert interval to seconds (`10m` → 600).
3. Start a background shell titled `Loop every <interval>: after-hours`, with `notify_on_output`:

```bash
while true; do
  sleep <seconds>
  echo 'AGENT_LOOP_TICK_after_hours {"prompt":"Continue /after-hours: read .after-hours/state.md and run the next tick."}'
done
```

4. Regex: `^AGENT_LOOP_TICK_after_hours`
5. Smoke-check startup once; store PID in `loop_pid` in state.
6. On each wake: read the latest sentinel line and run a tick.

## Tick protocol

On every tick (including the first):

1. Read `.after-hours/state.md`. If `status` is `stopped` / `done` / `stuck`, do not re-arm work; kill the loop if still running.
2. If `iteration >= max_iterations`: set status `done`, write final summary on the morning report, kill the loop, stop.
3. Increment `iteration` in state.
4. Choose **one** unchecked plan slice (or derive the next smallest slice from the goal / remaining `TODO.md` items).
5. Launch a **worker subagent** with a tight prompt:

```text
You are an after-hours worker for lock-security-checker.
Branch: development (already checked out by orchestrator).
Slice: <one concrete task>
Rules:
- Implement only this slice.
- Match existing project style.
- Laravel Sail is mandatory: never run bare php/composer/npm/artisan on the host.
  Use ./vendor/bin/sail <cmd> (artisan, composer, npm, php, …).
- Unattended: never ask the human for permission to run commands.
  For Sail/Docker/git push Shell calls, request required_permissions: ["all"] immediately.
- Before success: ./vendor/bin/sail artisan test
- If Sail is down: ./vendor/bin/sail up -d, then retest. If still down, report failure.
- If tests fail, fix within this slice or revert your broken changes and report failure.
- Do NOT commit, push, or force-push.
- Do NOT edit .after-hours/ or docs/after-hours/.
Return: (1) what you changed, (2) test result, (3) suggested commit message (conventional, concise), (4) wide description for the morning report (what/why/how, files touched, risks).
```

6. When the worker returns:
   - **No code changes** → log it; if nothing left on the plan, finish (status `done`).
   - **Tests failed / stuck** → append to Log; if 3 consecutive failed ticks, status `stuck`, finalize report, kill loop, stop.
   - **Success with changes** → you (orchestrator) commit and push:
     - `git status` / `git diff` / recent `git log` style check
     - Stage relevant files (never `.env` / secrets)
     - Commit with the worker's suggested message (HEREDOC)
     - `git push -u origin development`
     - Append a **Commits** section entry to the morning report (see below)
     - Check off the plan item; add follow-ups if the worker discovered more work
7. Update `.after-hours/state.md` Log with a short tick line.
8. Refresh the morning report **Summary** (running tally of progress / blockers).
9. End the turn. The fixed loop wakes the next tick; do not start a second sleeper.

## Morning report format

File: `docs/after-hours/YYYY-MM-DD.md` (loop start date, never rename mid-run).

After each successful commit, append:

```markdown
### <exact commit subject line>

<wide description from the worker: intent, approach, files, test outcome, leftover risks>

- **SHA:** <short sha>
- **Tick:** <n>
```

When the loop ends (`done`, `stuck`, max iterations, or `/after-hours-stop`), replace the Summary placeholder with a real wrap-up: what shipped, what failed, what a human should do next.

## Finish / stop

- Goal complete or plan empty → status `done`, finalize report, kill loop PID, confirm.
- User runs `/after-hours-stop` → that skill kills the loop; if you notice stop, finalize report if needed.
- Never leave a runaway sleeper without recording `loop_pid`.

## Safety

- No production deploys, secret exfiltration, or destructive git.
- No `git push --force`, `reset --hard`, or hook bypass.
- If Sail/Docker is down and tests cannot run, mark tick failed; after 3 failures stop as `stuck` with instructions in the report.

