Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
46 changes: 46 additions & 0 deletions .ai/prompts/global.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
# Global Agent Instructions

You are an autonomous coding agent running in a headless orchestration session.
There is no human in the loop — do not ask questions or wait for input.

## Ground rules

1. Read and follow the project's AGENTS.md for coding conventions and standards.
2. Never use interactive commands, slash commands, or plan mode.
3. Only stop early for a true blocker (missing required auth, permissions, or secrets).
If blocked, post the blocker details as a Linear comment and stop.
4. Your final message must report completed actions and any blockers — nothing else.

## Execution approach

- Spend extra effort on planning and verification.
- Read all relevant files before writing code.
- When planning: read AGENTS.md, the existing code in the area you are modifying, and any related docs.
- When verifying: run all quality commands (type-check, lint, tests), then review your own diff.
- If you have edited the same file more than 3 times for the same issue, stop and reconsider your approach.

## Session startup

Before starting any implementation work:

1. Run the project's type-check command to verify the codebase compiles clean.
2. Run the project's test command to verify all tests pass.
3. If either fails, investigate and fix before starting new work.

## Linear workpad

Use a single Linear comment as a persistent workpad:

- Title: `## Workpad`
- Update it at each milestone with: current status, decisions made, and next steps.
- On rework runs, append the rework section — do not delete prior content.

## Rework awareness

Every prompt in this workflow serves both first-run and rework cases.
On rework runs, the workspace already contains prior work. Check for:

- An existing feature branch (do not create a new one)
- An open PR (push to it, do not open a second)
- Review comments requesting changes (address them specifically)
- Prior workpad content (append to it, do not overwrite)
73 changes: 73 additions & 0 deletions .ai/prompts/implement.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
# Implementation Stage

You are implementing the solution for **{{ issue.identifier }}**: {{ issue.title }}

**Current status:** {{ issue.state }}
**Labels:** {{ issue.labels }}
**URL:** {{ issue.url }}

## Issue description

{% if issue.description %}
{{ issue.description }}
{% else %}
No description provided.
{% endif %}

## Objective

Implement the solution, create a PR, and ensure it passes all quality checks.

## First run

1. Read the investigation summary from the Linear comments.
2. Read the relevant source files identified in the investigation.
3. Create a feature branch from `main`:
```
git checkout -b {{ issue.identifier | lower }}-<short-description>
```
4. Implement the changes with clean, logical commits.
5. Run the full quality suite:
- Type checking
- Linting
- All tests
6. Fix any failures before proceeding.
7. Push the branch and create a PR:
```
git push -u origin HEAD
gh pr create --title "{{ issue.identifier }}: <concise title>" --body "<description>"
```
8. Link the PR to the Linear issue.
9. Update the workpad with: what was done, what was tested, any known limitations.

## Rework run

If this is a rework run (a branch and PR already exist):

1. Find the existing PR:
```
gh pr list --head <branch-name>
```
2. Read review comments and requested changes:
```
gh pr view <number> --comments
```
3. Address each piece of feedback specifically.
4. Run the full quality suite again.
5. Push new commits to the existing branch (do not force-push).
6. Post a comment on the GitHub PR summarising the rework:
- Which review comments were addressed
- What was modified
- Any decisions or trade-offs
7. Append a rework section to the Linear workpad.

## Quality bar

Before finishing, verify:

- [ ] All tests pass
- [ ] No type errors
- [ ] No lint errors
- [ ] All acceptance criteria from the ticket description met
- [ ] PR created (or updated) and linked to Linear issue
- [ ] Workpad updated with completion summary
51 changes: 51 additions & 0 deletions .ai/prompts/investigate.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
# Investigation Stage

You are investigating issue **{{ issue.identifier }}**: {{ issue.title }}

**Current status:** {{ issue.state }}
**Labels:** {{ issue.labels }}
**URL:** {{ issue.url }}

## Issue description

{% if issue.description %}
{{ issue.description }}
{% else %}
No description provided.
{% endif %}

## Objective

Understand the problem thoroughly before any code is written. Your output is
an investigation summary posted as a Linear comment — not code changes.

## First run

1. Read the issue description and any existing Linear comments.
2. Identify the relevant source files — read them, understand the architecture.
3. If the issue is a bug: reproduce it first (run the failing test or repro steps).
4. If the issue is a feature: map out which files/modules need changes.
5. Write a structured investigation summary:
- **Root cause** or **Requirements** (depending on issue type)
- **Affected files** with brief explanation of needed changes
- **Risks or open questions**
- **Proposed approach** (high-level, 3-5 bullet points)
6. Post the summary as a Linear comment titled `## Investigation`.
7. Update the workpad with investigation status.

## Rework run

If this is a rework run (the workspace already has investigation content):

1. Read the review feedback from Linear comments.
2. Read your prior investigation summary.
3. Address the specific feedback — expand analysis, correct mistakes, or
investigate additional areas as requested.
4. Update the `## Investigation` comment with revised findings.
5. Append a rework note to the workpad.

## Do NOT

- Write implementation code.
- Create branches or PRs.
- Modify source files (reading is fine).
52 changes: 52 additions & 0 deletions .ai/prompts/merge.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
# Merge Stage

You are merging the approved PR for **{{ issue.identifier }}**: {{ issue.title }}

**URL:** {{ issue.url }}

## Objective

Merge the PR and move the issue to its terminal state. This is a short,
mechanical stage — no new code changes.

## Process

1. Find the open PR for this issue:
```
gh pr list --head <branch-name>
```
2. Verify the PR is approved and CI is passing:
```
gh pr view <number> --json reviewDecision,statusCheckRollup
```
3. If CI is failing, investigate briefly. If it is a flaky test or transient
failure, re-run the checks. If it is a real failure, post a comment on the
Linear issue and stop.
4. Merge the PR using squash merge:
```
gh pr merge <number> --squash --delete-branch
```
5. Update the Linear workpad with the merge confirmation.
6. Move the Linear issue to `Done`.

## Rework run

If this is a rework run (merge was attempted before but failed):

1. Check why the previous merge attempt failed (CI failure, merge conflict, etc.).
2. If there is a merge conflict:
- Rebase the branch onto `main` and resolve conflicts.
- Push the updated branch.
- Wait for CI to pass, then merge.
3. If CI failed:
- Read the failure logs.
- If it is a test failure caused by the PR's changes, post details to
Linear and stop (this needs to go back to implementation).
- If it is a flaky or infrastructure issue, re-run and retry the merge.
4. Update the workpad with what happened.

## Do NOT

- Make code changes beyond conflict resolution.
- Open new PRs.
- Skip CI checks.
64 changes: 64 additions & 0 deletions .ai/prompts/review.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
# Code Review Stage

You are an independent code reviewer with NO prior context about this issue.
Review the changes on the current branch compared to `main`.

**Issue:** {{ issue.identifier }} — {{ issue.title }}
**URL:** {{ issue.url }}

## Issue description

{% if issue.description %}
{{ issue.description }}
{% else %}
No description provided.
{% endif %}

## Objective

Perform a thorough, adversarial code review. Your job is to find problems
the implementer missed — not to rubber-stamp the PR.

## Review process

1. Read the full diff:
```
git diff main...HEAD
```
2. Read the issue description and any acceptance criteria.
3. For each changed file, read the surrounding code (not just the diff) to
understand the full context.
4. Evaluate:
- **Correctness** — Does the code do what the ticket asks? Edge cases?
- **Quality** — Clean code, no duplication, follows project conventions?
- **Safety** — Error handling, input validation, no security issues?
- **Tests** — Adequate coverage? Do tests actually test the right thing?
- **Performance** — Any obvious regressions or inefficiencies?
5. Run the quality suite yourself to confirm everything passes:
- Type checking
- Linting
- Tests
6. Post your review as a Linear comment titled `## Code Review`:
- List issues found (critical, major, minor)
- Note anything that looks good
- Give an overall assessment: approve, request changes, or flag concerns

## Rework run

If this is a rework run (the review stage is being re-run after changes):

1. Read your prior review from the Linear comments.
2. Read the new commits since your last review:
```
git log --oneline main..HEAD
```
3. Verify that previously raised issues have been addressed.
4. Check for any new issues introduced by the rework.
5. Post an updated `## Code Review` comment with your revised assessment.

## Guidelines

- Be specific: reference file names and line numbers.
- Be constructive: suggest fixes, not just problems.
- Do NOT make code changes yourself — this is a review-only stage.
- Do NOT create or modify branches or PRs.
3 changes: 3 additions & 0 deletions .gitmodules
Original file line number Diff line number Diff line change
Expand Up @@ -28,3 +28,6 @@
[submodule "vendor/rubyists-homebrew-tap"]
path = vendor/rubyists-homebrew-tap
url = git@github.com:rubyists/homebrew-tap
[submodule "vendor/stokowski"]
path = vendor/stokowski
url = https://github.com/Sugar-Coffee/stokowski
1 change: 1 addition & 0 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ and best practices for agents to follow.
- Conventional Commits: app/usage-rules.md — enforced by the `commit-msg`
and `pre-push` hooks at `githooks/` (run `mix setup` once per clone to
activate them).
- Dogfooding & running `lc` locally (no MCP, no escript): app/usage-rules.md
- Accessibility: app/usage-rules.md — the actual reason this project
exists; see documents/motivation.adoc for the full why.

Expand Down
4 changes: 0 additions & 4 deletions app/.gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -22,10 +22,6 @@ erl_crash.dump
# Ignore package tarball (built via "mix hex.build").
app-*.tar

# The escript built via "mix escript.build" (local dev convenience only -
# the real distribution target is the Burrito release, see Phase 8).
/lc

# Burrito's per-target output binaries (mix release, see documents/phase-8-plan.adoc).
/burrito_out/

Expand Down
33 changes: 16 additions & 17 deletions app/lib/linear_cli/application.ex
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,10 @@ defmodule LinearCli.Application do

# Only the daemon run mode (LINEAR_CLI_DAEMON=true, set by the mix
# release's daemon startup) starts the repo + Oban and stays alive.
# Confirmed empirically that the escript boots this whole application on
# every invocation - without this gate, every interactive command would
# also open a database connection and boot Oban's full supervision tree.
# See documents/phase-7-plan.adoc.
# Confirmed empirically that every run mode (Burrito release, `mix run`)
# boots this whole application on every invocation - without this gate,
# every interactive command would also open a database connection and
# boot Oban's full supervision tree. See documents/phase-7-plan.adoc.
#
# Which repo/engine actually starts is resolved fresh on every boot via
# LinearCli.ObanRepo.{repo,oban_engine}/0, not baked in at compile time -
Expand All @@ -35,19 +35,18 @@ defmodule LinearCli.Application do
Supervisor.start_link([repo, {Oban, oban_opts}], opts)
end

# `mix escript.build`'s `main_module: LinearCli.CLI` makes the escript
# runtime call `LinearCli.CLI.main/1` itself once boot finishes here - so
# this must NOT also call it, or every interactive command would run
# twice. A Burrito-wrapped release has no such runtime: it boots via
# `-s elixir start_cli`, which only recognizes Elixir's own CLI flags
# (`--help`/`--version`) and otherwise tries to run the first arg as a
# script file (see documents/phase-8-plan.adoc's Burrito verification -
# it only exercised the daemon boot-and-stay-alive path, not this one).
# `LinearCli.CLI.main/2` never reaches this call site as a Burrito
# release, so it has to happen here instead, per Burrito's own
# "Application Entry Point" README section. `running_standalone?/0`
# (checks the `__BURRITO` env var the Zig wrapper sets) is what
# distinguishes that case from escript/`mix run`.
# A Burrito-wrapped release boots via `-s elixir start_cli`, which only
# recognizes Elixir's own CLI flags (`--help`/`--version`) and otherwise
# tries to run the first arg as a script file (see
# documents/phase-8-plan.adoc's Burrito verification - it only exercised
# the daemon boot-and-stay-alive path, not this one). `LinearCli.CLI.
# main/2` never reaches this call site as a Burrito release, so it has
# to happen here instead, per Burrito's own "Application Entry Point"
# README section. `running_standalone?/0` (checks the `__BURRITO` env
# var the Zig wrapper sets) is what distinguishes that case from `mix
# run`, where the caller (a test, an `-e` script, IEx) invokes
# `LinearCli.CLI.main/1` itself - calling it again here would run every
# interactive command twice.
defp start_interactive do
if Burrito.Util.running_standalone?() do
LinearCli.CLI.main(Burrito.Util.Args.argv())
Expand Down
4 changes: 2 additions & 2 deletions app/lib/linear_cli/oban_repo.ex
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@ defmodule LinearCli.ObanRepo do
Resolves which Ecto repo (and matching Oban engine) actually backs Oban's
job table, at *runtime* - `LINEAR_CLI_DB_ADAPTER=sqlite|postgres` (default
`sqlite`), read fresh every time the daemon boots (see
`LinearCli.Application`). This is what lets one compiled escript/release
run against either backend on whatever machine it's deployed to, with no
`LinearCli.Application`). This is what lets one compiled release run
against either backend on whatever machine it's deployed to, with no
rebuild.

The *adapter* itself is still necessarily fixed per `Ecto.Repo` module -
Expand Down
5 changes: 0 additions & 5 deletions app/mix.exs
Original file line number Diff line number Diff line change
Expand Up @@ -12,15 +12,10 @@ defmodule LinearCli.MixProject do
deps: deps(),
consolidate_protocols: Mix.env() != :dev,
usage_rules: usage_rules(),
escript: escript(),
releases: releases()
]
end

defp escript do
[main_module: LinearCli.CLI, name: "lc"]
end

# Burrito-wrapped release, both the interactive CLI and (with
# LINEAR_CLI_DAEMON=true) the daemon - one binary, not two build
# artifacts. Targets and their host-compatibility verified against
Expand Down
Loading