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
10 changes: 7 additions & 3 deletions RUBRIC.md
Original file line number Diff line number Diff line change
Expand Up @@ -131,9 +131,11 @@ Flag and subcommand removals are breaking changes caught by CI. Agents can depen
|---|-----------|------|-----|-----------|
| 3A.1 | `SKILL.md` embedded via `go:embed` | Yes | — | `skills/SKILL.md` |
| 3A.2 | `<cli> skill` prints embedded skill | Yes | — | `internal/commands/skill.go` |
| 3A.3 | `.claude-plugin/` with plugin.json, hooks, agents | Yes | — | `.claude-plugin/` |
| 3A.3 | `.claude-plugin/` with plugin.json, hooks, commands | Yes | — | `.claude-plugin/` |
| 3A.4 | SessionStart hook emits CLI context | Yes | — | `.claude-plugin/hooks/` |
| 3A.5 | Skill synced to `basecamp/skills` on release | Yes | — | `scripts/sync-skills.sh` |
| 3A.6 | `setup claude` installs plugin via marketplace | Yes | — | `internal/harness/claude.go`, `internal/commands/setup.go` |
| 3A.7 | Plugin registered in `basecamp/claude-plugins` marketplace | No | — | `basecamp/claude-plugins` marketplace.json |

### 3B. Pagination

Expand Down Expand Up @@ -219,9 +221,9 @@ For the **TUI tool profile**, score only the applicable tiers (1D, 4A, 4B, 4D) a
|------|-------|-----|
| T1: Agent Contract | /26 | 26 |
| T2: Reliability | /16 | 16 |
| T3: Agent Integration | /11 | 11 |
| T3: Agent Integration | /13 | 13 |
| T4: Distribution | /29 | 29 |
| **Total** | **/82** | **82** |
| **Total** | **/84** | **84** |

### Detailed Results

Expand Down Expand Up @@ -274,6 +276,8 @@ For the **TUI tool profile**, score only the applicable tiers (1D, 4A, 4B, 4D) a
| 3A.3 | `.claude-plugin/` | | | |
| 3A.4 | SessionStart hook | | | |
| 3A.5 | Skill synced on release | | | |
| 3A.6 | `setup claude` | | | |
| 3A.7 | Marketplace registration | | | |
| 3B.1 | `--limit N` | | | |
| 3B.2 | `--all` | | | |
| 3B.3 | Truncation notice | | | |
Expand Down
13 changes: 13 additions & 0 deletions prompts/close-gap.md
Original file line number Diff line number Diff line change
Expand Up @@ -48,3 +48,16 @@ Replace file-only credential storage with `credstore.NewStore()`. Set ServiceNam

### Adding surface stability (2A.2-3)
Use the `surface` package to generate snapshots. Commit the baseline. Add the `surface-compat` GitHub Action to CI.

### Adding setup claude (3A.6)
Create `internal/harness/claude.go` with `ClaudeMarketplaceSource` and `ClaudePluginName`
constants, plus `DetectClaude`, `FindClaudeBinary`, `IsPluginNeeded`, and `CheckClaudePlugin`
functions. Add a `setup claude` subcommand that runs marketplace add (best-effort) then
plugin install, with verify-after-install. Wire into the main setup wizard and add
breadcrumb suggestions via `harness.IsPluginNeeded()`.
Reference: github.com/basecamp/basecamp-cli/internal/harness/claude.go and wizard.go.

### Marketplace registration (3A.7)
Manual, external follow-up. Add a plugin entry to `basecamp/claude-plugins`
marketplace.json with source pointing at `basecamp/<app>-cli`. This is a one-time
step in the marketplace repo, not automatable from within the CLI repo.
9 changes: 9 additions & 0 deletions prompts/seed-cli.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ You are creating a new Go CLI for a 37signals product using the seed templates.
│ ├── auth/
│ ├── commands/
│ ├── config/
│ ├── harness/
│ └── output/
├── e2e/
├── skills/
Expand Down Expand Up @@ -83,9 +84,11 @@ You are creating a new Go CLI for a 37signals product using the seed templates.
- `seed/internal/commands/doctor.go.tmpl` → `internal/commands/doctor.go`
- `seed/internal/commands/setup.go.tmpl` → `internal/commands/setup.go`
- `seed/internal/commands/skill.go.tmpl` → `internal/commands/skill.go`
- `seed/internal/harness/claude.go.tmpl` → `internal/harness/claude.go` (fill in app name)

**Skills & plugin:**
- `seed/.claude-plugin/` → `.claude-plugin/` (customize)
- `mkdir -p .claude-plugin/skills && ln -s ../../skills/<app> .claude-plugin/skills/<app>` (create skills symlink)
- `seed/skills/app/SKILL.md.tmpl` → `skills/<app>/SKILL.md` (customize)
- `seed/skills/embed.go.tmpl` → `skills/embed.go`

Expand Down Expand Up @@ -157,6 +160,12 @@ After the repo is pushed to GitHub:
pip install pre-commit && pre-commit install --install-hooks
```

5. **Claude plugin marketplace** — register in `basecamp/claude-plugins`:
- Clone `basecamp/claude-plugins`
- Add entry to `.claude-plugin/marketplace.json` plugins array:
`{"name": "<app>", "description": "...", "source": {"source": "github", "repo": "basecamp/<app>-cli"}, "category": "productivity"}`
- PR and merge

## Auth Model Configuration

### OAuth + PKCE
Expand Down
40 changes: 0 additions & 40 deletions seed/.claude-plugin/agents/context-linker.md

This file was deleted.

48 changes: 0 additions & 48 deletions seed/.claude-plugin/agents/navigator.md

This file was deleted.

26 changes: 26 additions & 0 deletions seed/.claude-plugin/commands/doctor.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
---
name: {{.Name}}-doctor
description: Check {{.Name}} plugin health — CLI, auth, API connectivity, project context.
invocable: true
---

# /{{.Name}}-doctor

Run the {{.Name}} CLI health check and report results.

```bash
{{.Name}} doctor --json
```

Interpret the output:
- **pass**: Working correctly
- **warn**: Non-critical issue (e.g., shell completion not installed)
- **skip**: Check not run (e.g., unauthenticated or not applicable)
- **fail**: Broken — needs attention

For any failures, follow the `hint` field in the check output. Common fixes:
- Authentication failed → `{{.Name}} auth login`
- API unreachable → check network / VPN
- Plugin not installed → `{{.Name}} setup claude`

Report results concisely: list failures and warnings with their hints. If everything passes, say so.
27 changes: 27 additions & 0 deletions seed/.claude-plugin/hooks/hooks.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
{
"hooks": {
"SessionStart": [
{
"hooks": [
{
"type": "command",
"command": "${CLAUDE_PLUGIN_ROOT}/hooks/session-start.sh",
"timeout": 5
}
]
}
],
"PostToolUse": [
{
"matcher": "Bash",
"hooks": [
{
"type": "command",
"command": "${CLAUDE_PLUGIN_ROOT}/hooks/post-commit-check.sh",
"timeout": 5
}
]
}
]
}
}
72 changes: 72 additions & 0 deletions seed/.claude-plugin/hooks/post-commit-check.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
#!/usr/bin/env bash
# post-commit-check.sh - Check for {{.Name}} item references after git commits
#
# This hook runs after Bash tool use and checks if a git commit was made
# that references a {{.Name}} item ({{.Upper}}-12345, item-12345, etc.)

set -euo pipefail

# Require jq for JSON parsing
if ! command -v jq &>/dev/null; then
exit 0
fi

# Read tool input from stdin (JSON with tool_name, tool_input, tool_output)
input=$(cat)

# Extract tool input (the bash command that was run)
tool_input=$(echo "$input" | jq -r '.tool_input.command // empty' 2>/dev/null)
Comment thread
jeremy marked this conversation as resolved.

# Only process git commit commands
if [[ ! "$tool_input" =~ ^git\ commit ]]; then
exit 0
fi

# Check if commit succeeded by looking for output patterns
tool_output=$(echo "$input" | jq -r '.tool_output // empty' 2>/dev/null)

# Skip if commit failed — detect error indicators before checking for success.
# Only match lines that look like git/hook errors, not commit subject lines
# (e.g. "[branch abc1234] Fix failed login" should not trigger this guard).
# We strip the "[branch hash] subject" success line before scanning for errors.
filtered_output=$(echo "$tool_output" | grep -v '^\[.*[a-f0-9]\{7,\}\]' || true)
if echo "$filtered_output" | grep -qiE '(^|[[:space:]])(error|fatal|aborted|rejected)[[:space:]:]|hook[[:space:]].*[[:space:]]failed|pre-commit[[:space:]].*[[:space:]]failed|^error:'; then
exit 0
fi

# Verify commit actually succeeded - look for commit hash pattern or "create mode"
if [[ ! "$tool_output" =~ \[.*[a-f0-9]{7,}\] ]] && [[ ! "$tool_output" =~ "create mode" ]]; then
exit 0
fi

# Look for item references in the commit message or branch name
branch=$(git branch --show-current 2>/dev/null || true)
last_commit_msg=$(git log -1 --format=%s 2>/dev/null || true)

# Patterns: {{.Upper}}-12345, item-12345, {{.Name}}-12345
todo_patterns='{{.Upper}}-[0-9]+|item-[0-9]+|{{.Name}}-[0-9]+'

found_in_branch=$(echo "$branch" | grep -oEi "$todo_patterns" | head -1 || true)
found_in_msg=$(echo "$last_commit_msg" | grep -oEi "$todo_patterns" | head -1 || true)

if [[ -n "$found_in_branch" ]] || [[ -n "$found_in_msg" ]]; then
ref="${found_in_msg:-$found_in_branch}"
# Extract just the number
item_id=$(echo "$ref" | grep -oE '[0-9]+')

short_sha=$(git rev-parse --short HEAD 2>/dev/null || echo "unknown")
comment="Commit ${short_sha}: ${last_commit_msg}"
escaped_comment=$(printf '%q' "$comment")

cat << EOF
<hook-output>
Comment thread
jeremy marked this conversation as resolved.
Detected {{.Name}} item reference: $ref

To link this commit to {{.Name}}:
{{.Name}} comment ${escaped_comment} --on $item_id

Or complete the item:
{{.Name}} done $item_id
</hook-output>
EOF
fi
Loading
Loading