gini-bug-report
The gini-bug-report skill files locally captured and pre-redacted Gini crash reports as GitHub issues after obtaining user consent. Use it when the crash-report consent flow prompts the user to approve filing, or when the user explicitly requests reporting a captured crash. Do not use it for general GitHub issue work, non-crash bug reports, or any task requiring un-redacted data beyond the queued report itself.
git clone --depth 1 https://github.com/Lilac-Labs/gini-agent /tmp/gini-bug-report && cp -r /tmp/gini-bug-report/skills/dev/gini-bug-report ~/.claude/skills/gini-bug-reportSKILL.md
# Gini Bug Report
File a Gini crash that was captured locally — and redacted at capture time —
as a GitHub issue, but only after the user says yes. This skill is the
consent-aware orchestration layer on top of the `github-issues` skill: it
reads the pending crash queue, summarizes it for the user, and on a "yes"
delegates the actual `gh` filing to `github-issues`. It never invents crash
data and never re-reads raw logs.
## When To Use
- The crash-report consent flow invoked you: on restart of the `default`
instance, Gini posted a chat message asking whether to file captured
crash(es). The user replied in that thread — act on their answer here.
- The user explicitly asks to report a captured crash ("file that crash",
"report the crash you found").
## When NOT to Use
- General GitHub issue work (create/search/triage/label/close) → use the
`github-issues` skill directly; this skill only files queued crashes.
- A non-crash bug report, feature request, or any issue not already sitting
in the crash queue → use `github-issues` and write the body yourself.
- Anything that would need un-redacted data (raw `runtime.jsonl`, secrets,
full logs) → out of scope. The queued report is the trust boundary; never
go around it.
- Proactively scanning the queue or nagging the user → don't. Only act when
invoked by the consent flow or an explicit request.
## The crash queue
Approved `terminal_exec` runs with the working directory set to the
workspace root — **not** this skill's directory and **not** the crash
directory. Address the queue by ABSOLUTE path. Define it once and reuse it:
```bash
QUEUE="${GINI_STATE_ROOT:-$HOME/.gini}/crash-reports"
```
Layout:
- `$QUEUE/pending/*.json` — captured crashes awaiting a consent decision.
- `$QUEUE/filed/` — reports the user agreed to file (moved here after a
successful `gh` filing).
- `$QUEUE/dismissed/` — reports the user declined.
Each pending file is one JSON crash report with this shape (field names are
exact):
```
{ instance, source, supervisor, fingerprint, at,
error: { name, message, stack },
sysInfo: { platform, arch, nodeVersion, giniCommit },
logTail: [ { at, message }, ... ] }
```
**The report is ALREADY redacted at capture time.** Secrets, tokens, bearer
headers, and the `data` payload of every log line were stripped before the
file was written. Pass these fields through to the issue **as-is**. Do NOT
re-fetch raw logs, `runtime.jsonl`, secrets, or anything outside `$QUEUE` —
this report is published to GitHub, so the queued JSON is the only data you
are allowed to use.
## 1. List pending crashes
Read the queue and summarize each distinct crash for the user. Always quote
the file path so step 5 can resolve it later.
```bash
QUEUE="${GINI_STATE_ROOT:-$HOME/.gini}/crash-reports"
shopt -s nullglob
pending=("$QUEUE/pending"/*.json)
if [ ${#pending[@]} -eq 0 ]; then
echo "No pending crash reports."
else
for f in "${pending[@]}"; do
jq -r '"\(input_filename)
source: \(.source)
error: \(.error.name): \(.error.message)
at: \(.at)
fingerprint: \(.fingerprint)
"' "$f"
done
fi
```
If the queue is empty, tell the user there's nothing to report and stop —
do not file anything.
Multiple pending files can share one `fingerprint` (the same crash
recurring). Group by `fingerprint` — you file **one** issue per distinct
fingerprint (see step 3), not one per file.
## 2. Confirm intent — and scope to the asked fingerprints
The restart consent flow already asked the user the "want me to file this?"
question, so on this turn you are acting on their reply:
- **The user said yes** (or "report it", "go ahead") → proceed to step 3.
- **The user said no** (or "don't", "skip it") → file nothing; mark the
report(s) dismissed (step 5).
**File ONLY the fingerprints the consent named.** The consent message in
this conversation listed the specific crash fingerprint(s) it covers in full
(e.g. `The specific crash fingerprint(s) this consent covers (match these
EXACTLY): <64-hex-fingerprint>, ...`). A new crash can land in
`$QUEUE/pending` between the ask and the user's "yes"; filing it would be
unconsented. So when you list the queue in step 1, **match each pending file's
`.fingerprint` against the fingerprint(s) named in the consent message by
EXACT, full-string equality** (not by prefix — a short prefix could
misattribute a later same-prefix crash to this consent). Act on those files
only. You may display a shortened form to the user as cosmetic sugar, but the
file/dedup decision must use the exact fingerprint. Leave any pending file
whose fingerprint was not named where it is; a later consent flow will offer
it.
The one exception: if the user **explicitly** asks to file *all* pending
crashes ("file all of them", "report everything in the queue"), then act on
every pending file.
If you were invoked **manually** (the user asked directly, without the
consent message having been posted), ask first: summarize the pending
crash(es) from step 1 and ask whether to file them. Wait for the answer
before doing anything in step 3. Either way, confirm before filing.
## 3. On "yes" — file via github-issues
**Target repository.** A Gini crash is filed against the canonical Gini repo
— `Lilac-Labs/gini-agent` — NOT whatever git remote the current workspace
happens to have (the agent's working directory is a sandbox, not a Gini
checkout). Pass `--repo Lilac-Labs/gini-agent` to every `gh` call below.
Do not duplicate `gh` mechanics here. Load the `github-issues` skill and
follow its `gh` path — it handles installing `gh`, the interactive
`gh auth login` degrade, idempotent label creation, and create/search:
```
read_skill name='github-issues'
```
Then, **once per distinct fingerprint that the consent named** (skip any
pending file whose `.fingerprint` does not EXACTLY equal one named in the
consent message, unless the user explicitly asked to file all):
1. **Dedup first.** Search for an existing open crash issueDelegate coding work to Claude Code CLI for repository edits, reviews, and multi-turn implementation sessions.
Delegate coding work to the OpenAI Codex CLI for repository changes, reviews, and focused fixes.
Gini's self-knowledge: how Gini configures, extends, and operates on its own state via /api/* and registered tools. Load when the user asks Gini about its own capabilities or asks Gini to modify its own configuration.
Manage Apple Notes via memo CLI: create, search, edit.
Apple Reminders via remindctl: add, list, complete.
Move bytes between Gini upload space, external URLs, and workspace files. Used by every attachment / file-upload / file-download flow regardless of the target system (Linear, GitHub, S3, Notion, etc.).
Create, search, triage, label, assign, comment on, and close GitHub issues using the gh CLI, with a curl REST fallback.
Detection engine for Gmail email watches: iterates the watch list, polls gws for new matching mail per watch, dedups, drops automated/self, and hands matches (labeled by sender) to the shared drafting turn. Provisioned and run automatically by the shared email-watch backing job.