From 85a9b0317172ac4fd87f8967bf522a88219b3896 Mon Sep 17 00:00:00 2001 From: Mortdecai Date: Wed, 1 Apr 2026 17:51:39 -0400 Subject: [PATCH] docs: add design spec and implementation plan --- .../plans/2026-04-01-gitea-connector.md | 803 ++++++++++++++++++ .../2026-04-01-gitea-connector-design.md | 133 +++ 2 files changed, 936 insertions(+) create mode 100644 docs/superpowers/plans/2026-04-01-gitea-connector.md create mode 100644 docs/superpowers/specs/2026-04-01-gitea-connector-design.md diff --git a/docs/superpowers/plans/2026-04-01-gitea-connector.md b/docs/superpowers/plans/2026-04-01-gitea-connector.md new file mode 100644 index 0000000..a576609 --- /dev/null +++ b/docs/superpowers/plans/2026-04-01-gitea-connector.md @@ -0,0 +1,803 @@ +# Gitea Connector Plugin — Implementation Plan + +> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking. + +**Goal:** Build a Claude Code plugin that lets collaborators connect to Seth's Gitea instance (`git.sethpc.xyz`) with their own accounts, bundling a bash CLI, guided setup, commit conventions, and a push-reminder hook. + +**Architecture:** Claude Code plugin with `.claude-plugin/plugin.json` manifest. Slash command (`/gitea-setup`) invokes an agent for interactive credential setup. Skill provides commit conventions. Hook reminds to push after commits. Bash CLI in `bin/gitea` handles all API/git operations over HTTPS to `git.sethpc.xyz`. + +**Tech Stack:** Bash (CLI), Markdown with YAML frontmatter (plugin components), JSON (plugin manifest, hook config), `curl`/`jq`/`git` (CLI dependencies). + +**Spec:** `docs/superpowers/specs/2026-04-01-gitea-connector-design.md` + +--- + +## File Map + +| File | Action | Responsibility | +|------|--------|----------------| +| `.claude-plugin/plugin.json` | Create | Plugin manifest — name, description, paths to commands/agents/hooks | +| `bin/gitea` | Create | Bash CLI — create, remote, push, delete, list repos. HTTPS-only to `git.sethpc.xyz`. Reads username/token/host from `~/.config/gitea/` | +| `commands/gitea-setup.md` | Create | `/gitea-setup` slash command — invokes the setup agent | +| `agents/gitea-setup.md` | Create | Interactive setup agent — dependency check, credential collection, CLI install, token validation | +| `skills/gitea-workflow/SKILL.md` | Create | Commit conventions, CLI reference, credential safety, override mechanism | +| `hooks/hooks.json` | Create | Hook configuration — PostToolUse push reminder (disabled by default) | +| `hooks/scripts/push-reminder.sh` | Create | Detects `git commit` in Bash tool output, echoes push reminder | +| `README.md` | Create | User-facing install + usage docs | + +--- + +### Task 1: Plugin Manifest & Scaffold + +**Files:** +- Create: `gitea-connector/.claude-plugin/plugin.json` + +- [ ] **Step 1: Create the `.claude-plugin` directory** + +```bash +mkdir -p /home/claude/bin/gitea-connector/.claude-plugin +``` + +- [ ] **Step 2: Write `plugin.json`** + +```json +{ + "name": "gitea-connector", + "version": "1.0.0", + "description": "Connect Claude Code to Seth's Gitea instance (git.sethpc.xyz) — guided setup, CLI, commit conventions, and a gentle nudge to push.", + "author": { + "name": "Seth", + "url": "https://git.sethpc.xyz" + }, + "homepage": "https://git.sethpc.xyz/Seth/gitea-connector", + "repository": "https://git.sethpc.xyz/Seth/gitea-connector", + "license": "MIT", + "commands": ["./commands"], + "agents": ["./agents"], + "hooks": "./hooks/hooks.json" +} +``` + +- [ ] **Step 3: Create remaining directory structure** + +```bash +mkdir -p /home/claude/bin/gitea-connector/{commands,agents,skills/gitea-workflow,hooks/scripts,bin} +``` + +- [ ] **Step 4: Init git repo** + +```bash +cd /home/claude/bin/gitea-connector && git init +``` + +- [ ] **Step 5: Create `.gitignore`** + +``` +.backup/ +*.swp +*.swo +``` + +- [ ] **Step 6: Commit scaffold** + +```bash +cd /home/claude/bin/gitea-connector +git add .claude-plugin/plugin.json .gitignore +git commit -m "chore: scaffold plugin with manifest and directory structure" +``` + +--- + +### Task 2: Bash CLI (`bin/gitea`) + +**Files:** +- Create: `gitea-connector/bin/gitea` + +- [ ] **Step 1: Write the CLI script** + +Adapted from Seth's `~/bin/gitea`. Key changes: no LAN detection, reads username from config, silly help text. + +```bash +#!/usr/bin/env bash +# gitea — your friendly neighborhood Gitea CLI +# It creates repos. It pushes code. It occasionally judges your commit messages. +# Usage: gitea [options] + +set -euo pipefail + +# --- Config --- +GITEA_HOST="git.sethpc.xyz" +if [[ -f "$HOME/.config/gitea/host" ]]; then + GITEA_HOST="$(< "$HOME/.config/gitea/host")" + GITEA_HOST="${GITEA_HOST%%[[:space:]]}" +fi + +GITEA_USER="" +if [[ -f "$HOME/.config/gitea/username" ]]; then + GITEA_USER="$(< "$HOME/.config/gitea/username")" + GITEA_USER="${GITEA_USER%%[[:space:]]}" +fi +[[ -z "$GITEA_USER" ]] && { echo "ERROR: No username found. Run /gitea-setup or put your username in ~/.config/gitea/username" >&2; exit 1; } + +GITEA_TOKEN="${GITEA_TOKEN:-}" +if [[ -z "$GITEA_TOKEN" && -f "$HOME/.config/gitea/token" ]]; then + GITEA_TOKEN="$(< "$HOME/.config/gitea/token")" + GITEA_TOKEN="${GITEA_TOKEN%%[[:space:]]}" +fi +[[ -z "$GITEA_TOKEN" ]] && { echo "ERROR: No token found. Run /gitea-setup or put your token in ~/.config/gitea/token" >&2; exit 1; } + +API_BASE="https://${GITEA_HOST}/api/v1" + +# --- Helpers --- +api() { + local method="$1" endpoint="$2" + shift 2 + curl -sf -X "$method" "${API_BASE}${endpoint}" \ + -H "Content-Type: application/json" \ + -H "Authorization: token ${GITEA_TOKEN}" \ + "$@" +} + +# --- Commands --- +cmd_create() { + local name="" private=false description="" + while [[ $# -gt 0 ]]; do + case "$1" in + --private|-p) private=true; shift ;; + --public) private=false; shift ;; + --description|-d) description="$2"; shift 2 ;; + -*) echo "Unknown option: $1 (I don't know what that means and I'm too proud to guess)" >&2; exit 1 ;; + *) name="$1"; shift ;; + esac + done + [[ -z "$name" ]] && { echo "Usage: gitea create [--private] [--description \"...\"]"; echo " (You forgot the name. The repo needs a name. We all need names.)" >&2; exit 1; } + + local payload + payload=$(jq -n \ + --arg name "$name" \ + --argjson private "$private" \ + --arg desc "$description" \ + '{name: $name, private: $private, description: $desc, auto_init: false}') + + local resp + resp=$(api POST "/user/repos" -d "$payload") || { echo "FAIL: Gitea said no. Check your token and network." >&2; exit 1; } + + local html_url + html_url=$(echo "$resp" | jq -r '.html_url') + echo "Created: ${html_url}" + echo "Clone: https://${GITEA_HOST}/${GITEA_USER}/${name}.git" + echo "" + echo "Next up: 'gitea remote ${name}' to wire up your origin. You know the drill." +} + +cmd_remote() { + local name="${1:-}" + [[ -z "$name" ]] && { echo "Usage: gitea remote "; echo " (Which repo? I can't read minds. Yet.)" >&2; exit 1; } + + local url="https://${GITEA_HOST}/${GITEA_USER}/${name}.git" + + git config credential.helper 'store' + local cred_file="${HOME}/.git-credentials" + local cred_entry="https://${GITEA_USER}:${GITEA_TOKEN}@${GITEA_HOST}" + if ! grep -qF "${GITEA_HOST}" "$cred_file" 2>/dev/null; then + echo "$cred_entry" >> "$cred_file" + chmod 600 "$cred_file" + fi + + if git remote get-url origin &>/dev/null; then + git remote set-url origin "$url" + echo "Updated origin -> ${url}" + else + git remote add origin "$url" + echo "Added origin -> ${url}" + fi + echo "You're locked and loaded. 'gitea push' when ready." +} + +cmd_push() { + local branch + branch=$(git rev-parse --abbrev-ref HEAD 2>/dev/null) || { echo "This isn't a git repo. I checked." >&2; exit 1; } + echo "Pushing ${branch} to origin... hold onto your bits." + git push -u origin "$branch" +} + +cmd_delete() { + local name="${1:-}" + [[ -z "$name" ]] && { echo "Usage: gitea delete "; echo " (Delete what? Be specific. Destruction requires precision.)" >&2; exit 1; } + + read -rp "Delete ${GITEA_USER}/${name}? This is permanent. No take-backs. [y/N] " confirm + [[ "$confirm" =~ ^[Yy]$ ]] || { echo "Crisis averted. Repo lives another day."; exit 0; } + + if api DELETE "/repos/${GITEA_USER}/${name}"; then + echo "Deleted: ${GITEA_USER}/${name}. It's gone. Pour one out." + else + echo "FAIL: Could not delete ${GITEA_USER}/${name}. Maybe it's already gone? Maybe it's fighting back?" >&2; exit 1 + fi +} + +cmd_list() { + local resp + resp=$(api GET "/user/repos?limit=50&sort=updated") || { echo "FAIL: Couldn't fetch repos. Is Gitea awake?" >&2; exit 1; } + echo "$resp" | jq -r '.[] | "\(.name)\t\(if .private then "private" else "public" end)\t\(.description // "")"' | column -t -s$'\t' +} + +cmd_help() { + cat <<'EOF' +gitea — your friendly neighborhood Gitea CLI + +Usage: gitea [options] + +Commands: + create [--private] [--description "..."] Bring a new repo into this world + remote Wire up git origin with token auth + push Yeet current branch to origin + delete Send a repo into the void (confirms first) + list Show your repos (sorted by last updated) + +Examples: + gitea create my-project --private --description "Top secret stuff" + gitea remote my-project + gitea push + +Config files (~/.config/gitea/): + token Your API token (required) + username Your Gitea username (required) + host Gitea host override (default: git.sethpc.xyz) + +First time? Run /gitea-setup in Claude Code to get started. +EOF +} + +case "${1:-help}" in + create) shift; cmd_create "$@" ;; + remote) shift; cmd_remote "$@" ;; + push) shift; cmd_push "$@" ;; + delete) shift; cmd_delete "$@" ;; + list|ls) shift; cmd_list "$@" ;; + help|--help|-h) cmd_help ;; + *) echo "Unknown command: $1 (try 'gitea help' — I promise it's helpful)" >&2; exit 1 ;; +esac +``` + +- [ ] **Step 2: Make it executable** + +```bash +chmod +x /home/claude/bin/gitea-connector/bin/gitea +``` + +- [ ] **Step 3: Test CLI help output** + +```bash +/home/claude/bin/gitea-connector/bin/gitea help +``` + +Expected: The help text prints with all commands listed and silly flavor text. + +- [ ] **Step 4: Test CLI error handling (no config)** + +```bash +HOME=/tmp/fakehome /home/claude/bin/gitea-connector/bin/gitea list +``` + +Expected: Error about missing username, exit code 1. + +- [ ] **Step 5: Commit** + +```bash +cd /home/claude/bin/gitea-connector +git add bin/gitea +git commit -m "feat: add gitea bash CLI with silly personality" +``` + +--- + +### Task 3: Setup Agent + +**Files:** +- Create: `gitea-connector/agents/gitea-setup.md` + +- [ ] **Step 1: Write the setup agent** + +```markdown +--- +name: gitea-setup +description: Use this agent when a user needs to connect to the Gitea instance at git.sethpc.xyz. Walks them through API key generation, stores credentials, installs the CLI, and validates everything works. +model: inherit +--- + +You are the Gitea Setup Wizard — part helpful guide, part chaos goblin, fully committed to getting this human connected to git.sethpc.xyz without anyone crying. + +Your job: walk the user through connecting their Claude Code environment to Seth's Gitea instance. Be silly but get the job done. + +## Setup Steps + +Follow these steps IN ORDER. Use AskUserQuestion for each input step. Do not skip steps. + +### Step 1: Dependency Check + +Run these commands to verify dependencies: + +```bash +command -v curl >/dev/null 2>&1 && echo "curl: OK" || echo "curl: MISSING" +command -v jq >/dev/null 2>&1 && echo "jq: OK" || echo "jq: MISSING" +command -v git >/dev/null 2>&1 && echo "git: OK" || echo "git: MISSING" +``` + +If anything is MISSING, tell the user what to install and stop. Be dramatic about it: +- "Oh no. You don't have `jq`. That's like showing up to a sword fight with a pool noodle. Install it with `apt install jq` (or your distro's equivalent) and run /gitea-setup again." + +If all OK, proceed with enthusiasm. + +### Step 2: Check for Existing Config + +```bash +ls -la ~/.config/gitea/token 2>/dev/null && echo "EXISTS" || echo "NONE" +``` + +If EXISTS: Ask the user "You've already got Gitea credentials on file. Want to reconfigure? (This won't delete your repos, just your local config. Repos are forever. Well, until someone runs `gitea delete`.)" + +If they say no, stop gracefully: "Smart. If it ain't broke, don't authenticate it." + +### Step 3: Collect Username + +Ask the user: "What's your Gitea username? (This is your login name at git.sethpc.xyz — not your email, not your display name, not your gamer tag.)" + +Store the response for later. + +### Step 4: API Key Generation + +Tell the user exactly how to generate their token. Use this message: + +"Time to forge your API key. Here's the quest: + +1. Open **https://git.sethpc.xyz** in your browser and log in +2. Click your **profile picture** (top right corner — yes, that little circle) +3. Go to **Settings** +4. Click **Applications** in the sidebar +5. Under **Manage Access Tokens**, type `claude-code` as the token name +6. For permissions, check **repo** (Read and Write) and **user** (Read) +7. Click **Generate Token** +8. **COPY THE TOKEN NOW** — Gitea only shows it once. It's like a shooting star, except it grants repo access. + +Paste the token here when you've got it." + +Wait for the token via AskUserQuestion. + +### Step 5: Store Credentials + +Run these commands (substitute the actual username and token): + +```bash +mkdir -p ~/.config/gitea +echo "USERNAME_HERE" > ~/.config/gitea/username +echo "TOKEN_HERE" > ~/.config/gitea/token +chmod 600 ~/.config/gitea/username ~/.config/gitea/token +``` + +Replace USERNAME_HERE and TOKEN_HERE with the actual values collected. + +### Step 6: Install CLI + +Copy the CLI from the plugin to ~/bin/: + +```bash +mkdir -p ~/bin +cp "${CLAUDE_PLUGIN_ROOT}/bin/gitea" ~/bin/gitea +chmod +x ~/bin/gitea +``` + +Check if ~/bin is on PATH: + +```bash +echo "$PATH" | grep -q "$HOME/bin" && echo "ON_PATH" || echo "NOT_ON_PATH" +``` + +If NOT_ON_PATH, tell the user: "Heads up — `~/bin` isn't on your PATH. Add this to your `~/.bashrc` or `~/.zshrc`: + +```bash +export PATH=\"\$HOME/bin:\$PATH\" +``` + +Then restart your shell or run `source ~/.bashrc`. Otherwise `gitea` will just sit there, lonely and uncallable." + +### Step 7: Validate Token + +Test the token by calling the Gitea API: + +```bash +curl -sf "https://git.sethpc.xyz/api/v1/user" \ + -H "Authorization: token $(cat ~/.config/gitea/token)" | jq -r '.login' +``` + +Expected: The username they entered in Step 3. + +If the returned username matches: proceed to success. + +If it doesn't match: "Hmm, the token says you're `` but you told me ``. One of these is a lie. Which username is correct?" Then update ~/.config/gitea/username with their answer. + +If the request fails entirely: "That token didn't work. Gitea rejected it like a bouncer with standards. Double-check: +- Did you copy the whole token? (No leading/trailing spaces?) +- Did you actually click Generate? (The token only appears once!) +- Can you reach https://git.sethpc.xyz in a browser? + +Generate a new token and try /gitea-setup again." + +### Step 8: Success + +Print the victory message: + +"You're in! Here's what just happened: +- Credentials stored in `~/.config/gitea/` (locked down, chmod 600, very secure, much wow) +- CLI installed at `~/bin/gitea` +- Token validated against git.sethpc.xyz — you are who you say you are + +**Available commands:** +``` +gitea create [--private] [--description "..."] +gitea remote +gitea push +gitea delete +gitea list +``` + +**Quick start:** +```bash +mkdir my-project && cd my-project && git init +gitea create my-project --description "My cool thing" +gitea remote my-project +# write some code... +git add -A && git commit -m "feat: initial commit" +gitea push +``` + +Now go build something. The Gitea server believes in you. I believe in you. Your commits will be legendary." +``` + +- [ ] **Step 2: Commit** + +```bash +cd /home/claude/bin/gitea-connector +git add agents/gitea-setup.md +git commit -m "feat: add interactive gitea-setup agent with guided credential flow" +``` + +--- + +### Task 4: Setup Command (`/gitea-setup`) + +**Files:** +- Create: `gitea-connector/commands/gitea-setup.md` + +- [ ] **Step 1: Write the slash command** + +```markdown +--- +name: gitea-setup +description: Connect to Seth's Gitea instance (git.sethpc.xyz) — guided API key setup +--- + +Launch the gitea-setup agent to walk the user through connecting to the Gitea instance at git.sethpc.xyz. + +This command sets up: +1. API token credentials +2. The `gitea` CLI tool +3. Validates the connection works + +Dispatch the gitea-setup agent to handle this interactively. +``` + +- [ ] **Step 2: Commit** + +```bash +cd /home/claude/bin/gitea-connector +git add commands/gitea-setup.md +git commit -m "feat: add /gitea-setup slash command" +``` + +--- + +### Task 5: Gitea Workflow Skill + +**Files:** +- Create: `gitea-connector/skills/gitea-workflow/SKILL.md` + +- [ ] **Step 1: Write the skill** + +```markdown +--- +name: gitea-workflow +description: This skill should be used when working in a git repository with a git.sethpc.xyz remote, when the user asks to "commit", "push", "create a repo", "gitea", or when making changes to code that should be committed. Provides commit conventions, CLI reference, and credential safety rules. +--- + +# Gitea Workflow — Commit Conventions & CLI + +You're working with a repo hosted on Seth's Gitea instance (`git.sethpc.xyz`). Here's how we roll. + +## Commit Conventions (default-on, overridable) + +These conventions apply unless the project's CLAUDE.md says otherwise: + +- **Conventional commits:** Prefix every commit message with a type: + - `feat:` — new feature + - `fix:` — bug fix + - `docs:` — documentation only + - `refactor:` — code restructuring, no behavior change + - `test:` — adding or updating tests + - `chore:` — maintenance, tooling, deps +- **Commit immediately** — every meaningful change gets its own commit. Don't hoard changes. +- **Always push after commit** — use `gitea push` or `git push`. Code that isn't pushed is just a fancy diary entry. +- **No squashing** — every commit is a record. History is sacred (and also useful for debugging). +- **No batching unrelated changes** — one commit, one concern. If you changed the auth system AND updated the README, that's two commits. + +## CLI Reference + +The `gitea` CLI handles repo operations against git.sethpc.xyz: + +``` +gitea create [--private] [--description "..."] # Create a new repo +gitea remote # Set/update git origin with token auth +gitea push # Push current branch to origin +gitea delete # Delete a repo (with confirmation) +gitea list # List your repos +``` + +For creating a new project from scratch: +```bash +mkdir my-project && cd my-project && git init +gitea create my-project --description "What it does" +gitea remote my-project +# ... write code ... +git add -A && git commit -m "feat: initial commit" +gitea push +``` + +## Credential Safety + +**Never commit these:** +- `~/.config/gitea/token` or `~/.config/gitea/username` +- `.env` files containing secrets +- API keys, tokens, or passwords in any form + +**Always ensure `.gitignore` includes:** +``` +.env +.env.* +*.key +*.pem +``` + +If you see credentials in staged files, warn the user immediately and unstage them. + +## Override Mechanism + +Users can override any convention above in their project's CLAUDE.md. For example, if a project's CLAUDE.md says "squash commits before merge", follow that instead of these defaults. Project-level instructions always win. +``` + +- [ ] **Step 2: Commit** + +```bash +cd /home/claude/bin/gitea-connector +git add skills/gitea-workflow/SKILL.md +git commit -m "feat: add gitea-workflow skill with commit conventions and CLI reference" +``` + +--- + +### Task 6: Push Reminder Hook + +**Files:** +- Create: `gitea-connector/hooks/hooks.json` +- Create: `gitea-connector/hooks/scripts/push-reminder.sh` + +- [ ] **Step 1: Write the hook script** + +```bash +#!/usr/bin/env bash +# push-reminder.sh — nudges you to push after a commit +# Reads Bash tool output from stdin (JSON), checks if a git commit happened. + +set -euo pipefail + +INPUT=$(cat) +TOOL_NAME=$(echo "$INPUT" | jq -r '.tool_name // ""') +TOOL_RESULT=$(echo "$INPUT" | jq -r '.tool_result // ""') + +# Only trigger on Bash tool +[[ "$TOOL_NAME" == "Bash" ]] || exit 0 + +# Check if the output looks like a successful git commit +if echo "$TOOL_RESULT" | grep -qE '^\[.+\]\s+\S+'; then + echo '{"decision":"approve","systemMessage":"Commit detected! Friendly reminder: run `gitea push` to send it to git.sethpc.xyz. Unpushed commits are just really elaborate local notes."}' +else + echo '{"decision":"approve"}' +fi +``` + +- [ ] **Step 2: Make it executable** + +```bash +chmod +x /home/claude/bin/gitea-connector/hooks/scripts/push-reminder.sh +``` + +- [ ] **Step 3: Write hooks.json (hook disabled by default)** + +```json +{ + "description": "Gitea connector hooks — push reminder after commits (opt-in)", + "hooks": {} +} +``` + +Note: The hook is shipped disabled. To enable, users update `hooks.json` to: + +```json +{ + "description": "Gitea connector hooks — push reminder after commits", + "hooks": { + "PostToolUse": [ + { + "matcher": "Bash", + "hooks": [ + { + "type": "command", + "command": "bash ${CLAUDE_PLUGIN_ROOT}/hooks/scripts/push-reminder.sh", + "timeout": 5 + } + ] + } + ] + } +} +``` + +Document this in the README (Task 7). + +- [ ] **Step 4: Commit** + +```bash +cd /home/claude/bin/gitea-connector +git add hooks/hooks.json hooks/scripts/push-reminder.sh +git commit -m "feat: add push-reminder hook (opt-in, disabled by default)" +``` + +--- + +### Task 7: README + +**Files:** +- Create: `gitea-connector/README.md` + +- [ ] **Step 1: Write the README** + +```markdown +# gitea-connector + +A Claude Code plugin for connecting to Seth's Gitea instance at `git.sethpc.xyz`. Sets up your credentials, installs a CLI, and teaches Claude Code your commit conventions — so you can focus on writing code instead of remembering how to push it. + +## Install + +Add this plugin to your Claude Code setup: + +```bash +claude plugin add /path/to/gitea-connector +``` + +Or clone it: + +```bash +git clone https://git.sethpc.xyz/Seth/gitea-connector.git +claude plugin add ./gitea-connector +``` + +## Setup + +Run `/gitea-setup` in Claude Code. It'll walk you through everything: + +1. Checks you have `curl`, `jq`, and `git` (the holy trinity) +2. Guides you through generating an API token on git.sethpc.xyz +3. Stores your credentials securely in `~/.config/gitea/` +4. Installs the `gitea` CLI to `~/bin/` +5. Validates your connection + +The whole thing takes about 2 minutes. Less if you type fast. + +## CLI Usage + +After setup, you have the `gitea` command: + +```bash +gitea create my-project --private --description "Top secret stuff" +gitea remote my-project # wire up git origin +gitea push # push current branch +gitea list # see your repos +gitea delete old-project # delete (with confirmation) +``` + +## Commit Conventions + +The plugin teaches Claude Code these conventions (override in your project's CLAUDE.md): + +- **Conventional commits:** `feat:`, `fix:`, `docs:`, `refactor:`, `test:`, `chore:` +- **Commit immediately** — don't hoard changes +- **Always push** — unpushed commits are just elaborate local notes +- **No squashing** — history is sacred +- **One concern per commit** — no bundling unrelated changes + +## Push Reminder Hook (opt-in) + +Want a nudge after every commit? Edit `hooks/hooks.json` in the plugin directory: + +```json +{ + "description": "Gitea connector hooks — push reminder after commits", + "hooks": { + "PostToolUse": [ + { + "matcher": "Bash", + "hooks": [ + { + "type": "command", + "command": "bash ${CLAUDE_PLUGIN_ROOT}/hooks/scripts/push-reminder.sh", + "timeout": 5 + } + ] + } + ] + } +} +``` + +## Config Files + +All stored in `~/.config/gitea/`: + +| File | Purpose | +|------|---------| +| `token` | Your Gitea API token | +| `username` | Your Gitea username | +| `host` | (Optional) Host override, defaults to `git.sethpc.xyz` | + +## Requirements + +- `curl`, `jq`, `git` +- A Gitea account on `git.sethpc.xyz` (talk to Seth) +- Claude Code +``` + +- [ ] **Step 2: Commit** + +```bash +cd /home/claude/bin/gitea-connector +git add README.md +git commit -m "docs: add README with install, setup, and usage instructions" +``` + +--- + +### Task 8: Create Gitea Repo & Push + +**Files:** +- No new files + +- [ ] **Step 1: Create the Gitea repo** + +```bash +cd /home/claude/bin/gitea-connector +~/bin/gitea create gitea-connector --description "Claude Code plugin for connecting to Seth's Gitea instance" +``` + +- [ ] **Step 2: Set remote** + +```bash +cd /home/claude/bin/gitea-connector +~/bin/gitea remote gitea-connector +``` + +- [ ] **Step 3: Push all commits** + +```bash +cd /home/claude/bin/gitea-connector +~/bin/gitea push +``` + +Expected: All commits pushed to `https://git.sethpc.xyz/Seth/gitea-connector`. diff --git a/docs/superpowers/specs/2026-04-01-gitea-connector-design.md b/docs/superpowers/specs/2026-04-01-gitea-connector-design.md new file mode 100644 index 0000000..cd5841a --- /dev/null +++ b/docs/superpowers/specs/2026-04-01-gitea-connector-design.md @@ -0,0 +1,133 @@ +# Gitea Connector for Claude Code — Design Spec + +**Date:** 2026-04-01 +**Status:** Approved +**Author:** Seth + Claude + +## Overview + +A Claude Code plugin that lets collaborators connect to Seth's Gitea instance (`git.sethpc.xyz`) with their own accounts. Bundles an adapted bash CLI and provides guided setup, commit conventions, and Gitea-aware skills. + +**Target users:** Friends and collaborators Seth invites, who have their own Gitea accounts on `git.sethpc.xyz` and use Claude Code. + +## Plugin Structure + +``` +gitea-connector/ +├── plugin.json # Plugin manifest +├── commands/ +│ └── gitea-setup.md # /gitea-setup slash command +├── skills/ +│ └── gitea-workflow.md # Commit conventions & Gitea awareness +├── hooks/ +│ └── push-reminder.sh # Post-commit push reminder (opt-in) +├── agents/ +│ └── gitea-setup.md # Interactive setup agent +├── bin/ +│ └── gitea # Bash CLI (external-only, no LAN) +└── README.md +``` + +## Component Details + +### 1. Bash CLI (`bin/gitea`) + +Adapted from Seth's existing `~/bin/gitea` with these changes: + +- **Host:** Always `https://git.sethpc.xyz` — no LAN detection, no `192.168.0.125` references. All users are external. +- **Username:** Read from `~/.config/gitea/username` (not hardcoded to `Seth`). +- **Token:** Read from `~/.config/gitea/token` (same convention as original). +- **Host override:** Optional `~/.config/gitea/host` file for future flexibility, defaults to `git.sethpc.xyz`. + +Commands (unchanged interface): +``` +gitea create [--private] [--description "..."] +gitea remote +gitea push +gitea delete +gitea list +``` + +Drops the `api_base()` LAN/WAN probe function — replaced with a simple `https://${GITEA_HOST}/api/v1` base URL. + +### 2. Setup Flow (`/gitea-setup`) + +Invokes the `gitea-setup` agent for interactive credential setup. + +**Steps:** + +1. **Dependency check:** Verify `curl`, `jq`, `git` are installed. If missing, tell the user what to install and stop. +2. **Existing config check:** If `~/.config/gitea/token` exists, ask if they want to reconfigure. +3. **Collect username:** Ask the user for their Gitea username. +4. **Walk through API key generation:** + > Go to `https://git.sethpc.xyz` → click your **profile icon** (top right) → **Settings** → **Applications** → under **Manage Access Tokens**, name it `claude-code`, grant **repo** (read/write) and **user** (read) permissions, click **Generate Token** → paste the token back here. +5. **Store credentials:** + - Create `~/.config/gitea/` if missing + - Write `token` and `username` files + - `chmod 600` both files +6. **Install CLI:** + - Copy `bin/gitea` to `~/bin/gitea` + - `chmod +x ~/bin/gitea` + - If `~/bin` not on PATH, warn and suggest adding it +7. **Validate:** `GET /api/v1/user` with the token, confirm returned username matches what they entered. +8. **Success message:** Confirm everything works, list available commands. + +**Tone:** Silly but appropriate throughout the entire experience — the setup agent's conversational messages, CLI help text, success/error messages, and skill descriptions should all have personality. Think friendly chaos goblin who knows their way around git, not corporate onboarding wizard. + +### 3. Skill (`skills/gitea-workflow.md`) + +Loaded into Claude Code's context when working in repos with a `git.sethpc.xyz` origin. Provides: + +- **Commit conventions (default-on, overridable):** + - Conventional commits: `feat:`, `fix:`, `docs:`, `refactor:`, `test:`, `chore:` + - Commit every meaningful change immediately + - Always push after commit + - No squashing, no batching unrelated changes +- **Gitea CLI usage:** Reference for `gitea create`, `remote`, `push`, `delete`, `list` +- **Credential safety:** Never commit tokens; ensure `.gitignore` covers `.env`, credential files, `~/.config/gitea/` +- **Override mechanism:** Users can override any convention in their project's CLAUDE.md + +Trigger condition: Skill activates when current repo's origin URL contains `git.sethpc.xyz`. + +### 4. Hook (`hooks/push-reminder.sh`) + +- **Type:** PostToolUse hook on the `Bash` tool +- **Trigger:** Detects successful `git commit` in command output +- **Action:** Echoes a reminder to push +- **Default:** Disabled (opt-in via plugin settings) + +### 5. Agent (`agents/gitea-setup.md`) + +The interactive agent behind `/gitea-setup`. Uses `AskUserQuestion` to collect input step by step. Handles all the logic described in the setup flow above. + +## Error Handling + +| Scenario | Behavior | +|----------|----------| +| Token invalid / expired | "That token didn't work. Generate a new one at Settings → Applications." | +| Gitea unreachable | "Can't reach git.sethpc.xyz. Check your network or VPN connection." | +| `~/bin` not on PATH | Warn and suggest adding it to shell profile | +| Token file exists, re-running setup | "Found existing config. Reconfigure? (y/N)" | +| `jq` / `curl` / `git` not installed | Check at start, list what's missing | +| Username mismatch (token returns different user) | "Token belongs to but you said . Which is correct?" | + +## Networking + +- **Always HTTPS to `git.sethpc.xyz`** (Caddy reverse proxy to Gitea CT 146) +- No LAN IP references anywhere — all users are external +- Default host overridable via `~/.config/gitea/host` file + +## Dependencies + +- `curl` — API calls +- `jq` — JSON parsing +- `git` — repo operations + +No other external dependencies. Pure bash CLI. + +## Out of Scope + +- Multi-instance support (connecting to arbitrary Gitea servers) +- User account creation on Gitea (Seth invites users manually) +- SSH key setup (HTTPS + token auth only) +- CI/CD integration