Compare commits

...

8 Commits

Author SHA1 Message Date
Murphy Freelance
29d0b1990d fix: review findings — env-var netrc write hygiene, network-vs-auth errors, installer collision guard, docs
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-10 19:48:42 +02:00
Murphy Freelance
f99666bf8a docs: Codex CLI install/usage instructions; bump to 0.3.0
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-10 19:37:49 +02:00
Murphy Freelance
bf92d05df2 feat(map-repo): platform-neutral root resolution and survey
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-10 19:34:38 +02:00
Murphy Freelance
79834fee3f feat(triage): dual MCP/REST mode with shared netrc credentials
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-10 19:31:32 +02:00
Murphy Freelance
6525f60f86 feat(setup): store credentials in shared netrc, migrate legacy env vars
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-10 19:27:48 +02:00
Murphy Freelance
ec853559af feat: add Codex CLI installer (symlinks into ~/.agents/skills)
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-10 19:24:52 +02:00
Murphy Freelance
a7dcc361c0 docs: implementation plan for Codex support; fix search endpoint to v3 search/jql
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-10 19:22:10 +02:00
Murphy Freelance
a967f5c38e docs: design for Codex CLI support
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-10 19:16:19 +02:00
8 changed files with 1243 additions and 124 deletions

View File

@@ -1,7 +1,7 @@
{
"name": "gw-triage",
"description": "Da screenshot + messaggio Telegram a issue Jira instradata al dev giusto",
"version": "0.2.0",
"version": "0.3.0",
"author": {
"name": "GrowingWay"
}

View File

@@ -5,6 +5,8 @@ assegnata al dev giusto.
## Installazione (una volta sola)
### Claude Code
1. **Plugin Atlassian** — in Claude Code:
`/plugin install atlassian@claude-plugins-official`
2. **Login Atlassian** — esegui `/mcp`, seleziona `atlassian` e completa
@@ -16,27 +18,45 @@ assegnata al dev giusto.
4. **Token API** (per allegare gli screenshot — facoltativo ma
consigliato): esegui `/gw-triage:setup` e segui le istruzioni.
### Codex CLI
1. Clona il repo dove preferisci:
`git clone https://git.growingway.com/giuse/gw-triage.git`
2. Dalla cartella clonata esegui `./install-codex.sh` — crea i link
alle skill in `~/.agents/skills/`. Nota: le skill si chiamano
`triage`, `setup` e `map-repo`; se hai già altre skill con questi
nomi entrano in conflitto.
3. **Token API** (qui obbligatorio — su Codex tutte le chiamate Jira
lo usano): invoca `$setup` e segui le istruzioni.
Per aggiornare: `git pull` nella cartella clonata (i link restano
validi). Su Claude Code: `/plugin marketplace update gw-triage`.
## Token API Jira
Serve solo ad allegare gli screenshot alle issue (l'MCP Atlassian non
supporta gli allegati). Senza token tutto funziona lo stesso: viene
saltato solo l'allegato.
Su Claude Code serve solo ad allegare gli screenshot alle issue (le
altre operazioni passano dall'MCP Atlassian): senza token tutto
funziona lo stesso, viene saltato solo l'allegato. Su Codex invece è
obbligatorio: tutte le chiamate Jira lo usano.
Esegui `/gw-triage:setup` in Claude Code: ti guida nella creazione del
token dalla pagina Atlassian, te lo chiede, lo verifica e lo salva da
solo. Niente configurazione manuale della shell.
Esegui il setup (`/gw-triage:setup` su Claude Code, `$setup` su
Codex): ti guida nella creazione del token dalla pagina Atlassian, te
lo chiede, lo verifica e lo salva in `~/.config/gw-triage/netrc`
(valido da subito, senza riavviare nulla). Se avevi già configurato il
token in `~/.claude/settings.json`, il setup lo migra da solo.
⚠️ Il token agisce a tuo nome su Jira: non condividerlo. Se trapela,
revocalo da <https://id.atlassian.com/manage-profile/security/api-tokens>.
Quando scade, `/gw-triage:triage` continua a funzionare — salta solo
l'allegato: rilancia `/gw-triage:setup` per sostituirlo.
Quando scade: su Claude Code `/gw-triage:triage` continua a funzionare
(salta solo l'allegato), su Codex si ferma e ti rimanda al setup.
Rilancia il setup per sostituirlo.
## Uso quotidiano
1. In Claude Code allega uno screenshot (**trascina il file nel
prompt**, così può essere allegato alla issue) e/o scrivi una breve
descrizione del problema, sufficiente a identificarlo, poi invoca
`/gw-triage:triage`.
1. Allega uno screenshot (**trascina il file nel prompt**, così può
essere allegato alla issue) e/o scrivi una breve descrizione del
problema, sufficiente a identificarlo, poi invoca
`/gw-triage:triage` (Claude Code) o `$triage` (Codex).
2. Rispondi all'eventuale domanda di chiarimento, conferma la bozza →
la issue viene creata e ricevi il link.
@@ -46,15 +66,20 @@ l'allegato va poi trascinato in Jira a mano.
## Aggiornare la conoscenza dei repo
Quando la tua codebase cambia in modo visibile agli utenti, dalla
cartella del repo esegui `/gw-triage:map-repo` e segui le istruzioni:
cartella del repo esegui `/gw-triage:map-repo` (Claude Code) o
`$map-repo` (Codex) e segui le istruzioni:
il profilo aggiornato viene pushato qui e gli altri lo ricevono con
`/plugin marketplace update gw-triage`.
`/plugin marketplace update gw-triage` (Claude Code) o `git pull`
nella cartella clonata (Codex).
## Problemi comuni
- **"MCP Atlassian non disponibile"** → passi 12 dell'installazione.
- **"Allegato saltato"** → esegui `/gw-triage:setup` (token mancante,
scaduto o sessione da riavviare).
- **"MCP Atlassian non disponibile"** → passi 12 dell'installazione
Claude Code.
- **"Allegato saltato"** → esegui il setup (token mancante, scaduto o
revocato).
- **Su Codex le skill non compaiono** → riesegui `./install-codex.sh`
dalla cartella clonata e controlla i link in `~/.agents/skills/`.
- **La issue finisce nell'epic sbagliata** → correggi in Jira e apri
una issue su questo repo per aggiustare `config/routing.json` o il
profilo in `knowledge/`.

View File

@@ -0,0 +1,172 @@
# gw-triage — Codex CLI support
Date: 2026-07-10
Status: approved
## Problem
The plugin only runs under Claude Code: distribution relies on the
Claude plugin marketplace, skills locate their data via
`${CLAUDE_PLUGIN_ROOT}`, Jira access goes through the Atlassian MCP
plugin, and credentials live in the `env` block of
`~/.claude/settings.json`. Teammates on OpenAI Codex CLI can't use any
of it. Goal: full parity — `triage`, `setup`, and `map-repo` all work
on Codex, from the same repo, with no duplicated skill files.
## Decisions (agreed 2026-07-10)
1. **Scope**: full parity for all three skills.
2. **Jira transport on Codex**: plain REST via curl with the Jira API
token. No MCP configuration on Codex. Claude Code keeps its MCP
path unchanged.
3. **Skill files**: one SKILL.md per skill, shared by both platforms,
branching internally where behavior differs.
4. **Credentials**: a single netrc file at `~/.config/gw-triage/netrc`
used by curl on both platforms, replacing the settings.json env
block as the primary store.
## Verified platform facts
- Codex discovers skills in `.agents/skills` (project, walking up to
repo root) and `~/.agents/skills` (user level). Symlinked skill
directories are followed.
- Skills use the same SKILL.md format (frontmatter `name` +
`description`); invoked explicitly as `$<name>` or implicitly via
the description.
- Codex's `[shell_environment_policy]` env injection filters names
containing `TOKEN` by default and has open reliability issues —
ruled out in favor of the netrc file.
- Jira Cloud REST API v2 (`/rest/api/2/…`) is still served and accepts
plain-text descriptions, avoiding the ADF JSON required by v3
`createIssue`. v2 is legacy; if Atlassian retires it, the REST-mode
steps move to v3 + minimal ADF paragraphs.
## Design
### 1. Distribution
Repo structure unchanged. Codex users clone the repo anywhere and
symlink each skill directory into `~/.agents/skills/`:
~/.agents/skills/triage -> <clone>/skills/triage
~/.agents/skills/setup -> <clone>/skills/setup
~/.agents/skills/map-repo -> <clone>/skills/map-repo
A small `install-codex.sh` at the repo root creates/refreshes the
symlinks idempotently. Updates arrive with `git pull` in the clone.
Skill names stay as-is so Claude Code commands don't change
(`/gw-triage:triage`). On Codex they are `$triage`, `$setup`,
`$map-repo`; the generic names could collide with other installed
skills — accepted risk for a three-person team, noted in the README.
### 2. Platform detection and root resolution
Each SKILL.md gets a short "Environment" preamble:
- **Root**: `${CLAUDE_PLUGIN_ROOT}` if set; otherwise resolve the real
path (symlinks followed) of the skill's own directory and go up two
levels. `config/` and `knowledge/` are addressed relative to that
root everywhere.
- **Mode** (triage only): Atlassian MCP tools available → MCP mode
(today's behavior, unchanged); otherwise → REST mode.
### 3. Credentials — netrc file
`setup` writes `~/.config/gw-triage/netrc`:
machine growingway.atlassian.net
login <email>
password <token>
(machine host derived from `site` in routing.json), `chmod 600`. Every
curl call on both platforms passes `--netrc-file
~/.config/gw-triage/netrc`, read at call time — no session restart
needed after setup, and no secrets on command lines or in process
listings.
`setup` itself becomes platform-neutral (file operations + curl only):
- Verify pasted credentials against `GET /rest/api/2/myself` before
saving (3-attempt limit, network-vs-auth error distinction — as
today).
- **Migration**: if credentials already exist in the session env or in
`~/.claude/settings.json` `env`, verify them and migrate them into
the netrc automatically; suggest removing the settings.json entries
(leftover shell-profile check stays).
- The temp-netrc-for-literals dance disappears: the real netrc file IS
the store, written before verification and deleted only if
verification ultimately fails.
`triage` reads the netrc as the primary credential source and falls
back to `JIRA_EMAIL`/`JIRA_API_TOKEN` env vars (legacy installs) for
the attachment step.
### 4. Triage in REST mode
Used on Codex. (Claude Code without MCP still stops and points at the
Atlassian plugin install, as today — MCP remains the intended path
there.)
On Codex the token is **required** — it is the only transport. Missing
or invalid netrc → stop with `$setup` instructions.
| Step | MCP mode (unchanged) | REST mode |
|---|---|---|
| Preflight | `getAccessibleAtlassianResources` | `GET /rest/api/2/myself` → expect 200 |
| Duplicate search | `searchJiraIssuesUsingJql` | `GET /rest/api/3/search/jql?jql=<urlencoded>` (the v2/v3 `/search` endpoints were removed by Atlassian in 2025) |
| Create | `createJiraIssue` | `POST /rest/api/2/issue` (JSON body: project, issuetype, summary, plain-text description, assignee accountId, parent epic) |
| Comment on duplicate | `addCommentToJiraIssue` | `POST /rest/api/2/issue/{key}/comment` |
| Attach screenshot | curl (as today) | same curl, `--netrc-file` |
`cloudId` in routing.json becomes MCP-only; REST mode uses `site`.
Classification, drafting, confirmation flow, and Italian interaction
are identical in both modes.
### 5. map-repo
Two touch-ups:
- Root resolution per §2 (replaces `${CLAUDE_PLUGIN_ROOT}`).
- Survey step: "dispatch one exploration subagent **if the platform
supports subagent dispatch; otherwise perform the survey yourself**,
covering the same six points."
- Publish step: note that Codex teammates receive updates with
`git pull` in their clone (Claude Code users keep
`/plugin marketplace update gw-triage`).
### 6. README
- New "Installazione (Codex)" section: clone, `./install-codex.sh`,
run `$setup`, daily use via `$triage`.
- Token section updated: netrc path, token optional on Claude Code
(attachments only), **required** on Codex.
- Per-platform update instructions and troubleshooting entries.
## Error handling
- REST calls: treat non-2xx as failure; show the raw body with a
one-line Italian summary. Create-issue failure stops before the
attachment step (nothing partial), as today.
- Netrc unreadable/missing on Codex → stop with setup guidance; on
Claude Code → warn once that attachment will be skipped, proceed.
- JQL must be URL-encoded in REST mode (curl `--data-urlencode` with
`-G`).
## Testing
- REST commands exercised directly against Jira: `myself`, JQL search,
create on a throwaway issue, comment, attachment — then delete the
throwaway.
- Codex smoke test: skills discovered after `install-codex.sh`,
`$triage` dry run reaches the draft step, `$setup` full run.
- Claude Code regression: `/gw-triage:triage` full run with netrc in
place (MCP mode + netrc attachment), `/gw-triage:setup` migration
path from settings.json env vars.
## Out of scope
- Renaming skills or namespacing for Codex.
- Moving Claude Code off MCP.
- Windows support (team is on macOS).
- v3/ADF migration (documented as future work if v2 is retired).

773
docs/codex-support-plan.md Normal file
View File

@@ -0,0 +1,773 @@
# Codex CLI Support 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:** Make the gw-triage skills (triage, setup, map-repo) work under OpenAI Codex CLI with full parity, from the same repo, without breaking the Claude Code flow.
**Architecture:** Shared SKILL.md files that resolve their root via `${CLAUDE_PLUGIN_ROOT}` or their own real path, branch between Atlassian MCP (Claude Code) and Jira REST v2 via curl (Codex), and read credentials from a single netrc file at `~/.config/gw-triage/netrc` written by the setup skill. Codex installation = clone + symlinks into `~/.agents/skills/` created by `install-codex.sh`.
**Tech Stack:** SKILL.md (Agent Skills spec), POSIX sh, curl, Jira Cloud REST API v2.
**Spec:** `docs/codex-support-design.md` (approved 2026-07-10).
## Global Constraints
- All user interaction in the skills happens in Italian; SKILL.md prose stays in English.
- Never put a literal token on a shell command line or in a reply; credentials move only via files (netrc, mode 600) or unexpanded `$VAR` references.
- Netrc path is exactly `~/.config/gw-triage/netrc`. Codex skills dir is exactly `~/.agents/skills`.
- Jira REST calls use API v2 (`/rest/api/2/…`) except attachments (`/rest/api/3/issue/<KEY>/attachments`) and JQL search (`/rest/api/3/search/jql` — the v2 search endpoint was removed by Atlassian in 2025).
- On Claude Code without MCP, triage STOPS with the install guide — REST mode is not a fallback there.
- On Codex the token is REQUIRED; on Claude Code it remains optional (attachments only).
- Skill frontmatter `name:` values must not change (`triage`, `setup`, `map-repo`) — they define the Claude Code commands.
- Claude Code MCP behavior in triage is unchanged: same tools, same cloudId usage.
---
### Task 1: `install-codex.sh`
**Files:**
- Create: `install-codex.sh` (repo root, executable)
**Interfaces:**
- Produces: idempotent script that symlinks `skills/{triage,setup,map-repo}` into `~/.agents/skills/`. README (Task 5) references it as `./install-codex.sh`.
- [ ] **Step 1: Write the script**
```sh
#!/bin/sh
# Install the gw-triage skills for OpenAI Codex CLI by symlinking them
# into ~/.agents/skills. Safe to re-run; updates arrive via `git pull`
# in this clone (symlinks keep pointing at the updated files).
set -eu
repo_dir=$(CDPATH= cd -- "$(dirname -- "$0")" && pwd -P)
dest="${HOME}/.agents/skills"
mkdir -p "$dest"
for skill in triage setup map-repo; do
ln -sfn "$repo_dir/skills/$skill" "$dest/$skill"
echo "linked $dest/$skill -> $repo_dir/skills/$skill"
done
echo "Fatto. Per aggiornare in futuro: git -C \"$repo_dir\" pull"
```
- [ ] **Step 2: Make it executable and verify against a scratch HOME**
Run (fish syntax, since the user shell is fish; use `bash -c` to keep it portable):
```bash
chmod +x install-codex.sh
bash -c 'HOME=$(mktemp -d) && ./install-codex.sh && ls -l "$HOME/.agents/skills" && readlink "$HOME/.agents/skills/triage"'
```
Expected: three `linked …` lines, `ls` shows `map-repo`, `setup`, `triage` as symlinks, `readlink` prints `<repo>/skills/triage`. Re-run the script against the same HOME to confirm idempotency (no error, same links).
- [ ] **Step 3: Commit**
```bash
git add install-codex.sh
git commit -m "feat: add Codex CLI installer (symlinks into ~/.agents/skills)"
```
---
### Task 2: Rewrite `skills/setup/SKILL.md` for the shared netrc store
**Files:**
- Modify: `skills/setup/SKILL.md` (full rewrite of the body; frontmatter `name` unchanged)
**Interfaces:**
- Produces: credentials at `~/.config/gw-triage/netrc` in the format `machine <host>` / `login <email>` / `password <token>`, mode 600. Task 3 (triage) consumes this file via `curl --netrc-file`.
- [ ] **Step 1: Replace the file content**
Write `skills/setup/SKILL.md` with exactly:
````markdown
---
name: setup
description: Use when configuring the Jira API credentials for gw-triage — first-time setup, an "allegato saltato" warning from triage, missing or expired credentials, or replacing a revoked token. Triggers on /gw-triage:setup, $setup, "configura il token", "gli allegati non funzionano".
---
# Setup — token API Jira guidato
You guide the user through creating a Jira API token and storing it in
the gw-triage netrc file. The `triage` skill reads that file for its
REST calls: screenshot attachments on every platform, plus search /
create / comment when running under Codex.
**All interaction with the user happens in Italian.** This file is
English for precision; never quote it to the user.
## Environment
- **Root**: `${CLAUDE_PLUGIN_ROOT}` if that variable is set; otherwise
the real path of this skill's own directory (resolve symlinks, e.g.
with `realpath`), two levels up.
- **Store**: `~/.config/gw-triage/netrc`, mode 600. curl reads it at
call time on every platform, so changes take effect immediately — no
session restart, no shell configuration.
- **Host**: the `site` value in `<root>/config/routing.json` without
the scheme (e.g. `growingway.atlassian.net`).
**Keep the token out of replies and displayed commands.** Refer to it
as "il token" and never repeat its value. Never inline a literal token
on a shell command line — it ends up in the transcript and the process
list. Write credentials into the netrc file with the file-writing
tool, then let curl read them via `--netrc-file`.
The verification call used throughout:
curl -s -o /dev/null -w "%{http_code}" \
--netrc-file ~/.config/gw-triage/netrc \
https://<host>/rest/api/2/myself
## Step 0 — Check existing configuration
1. If `~/.config/gw-triage/netrc` exists and is readable, run the
verification call.
- `200` → tell the user (Italian) the token already works and ask
whether they want to replace it anyway. If not, stop.
- anything else → tell them the stored token no longer works
(probably expired or revoked) and continue to Step 1.
2. Otherwise look for legacy credentials, in order:
- session env: `test -n "$JIRA_EMAIL" && test -n "$JIRA_API_TOKEN" && echo session || echo unset`
- `~/.claude/settings.json` (if it exists): `env.JIRA_EMAIL` /
`env.JIRA_API_TOKEN`.
If found in either place: write them to the netrc (Step 2 format,
chmod 600) and run the verification call.
- `200` → tell the user (Italian) the existing credentials were
migrated to the new store and work immediately; then do Step 3
(clean up legacy stores) and Step 4. Done — skip token creation.
- anything else → delete the netrc just written, tell them the old
token no longer works, continue to Step 1.
3. Nothing found → first-time setup, continue to Step 1.
## Step 1 — Token creation (user, in the browser)
Print in Italian, compactly:
1. Apri <https://id.atlassian.com/manage-profile/security/api-tokens>
(login con l'account Atlassian aziendale).
2. **Create API token** → nome `gw-triage` → scegli la scadenza →
**copia subito il token** (viene mostrato una volta sola).
3. Incolla qui email aziendale e token (vanno bene anche su due righe).
Add one line: il token verrà salvato in chiaro in
`~/.config/gw-triage/netrc` sul suo computer, quindi non condividere né
il file né questa conversazione.
End the turn and wait. If the reply contains only one of the two
values, ask for the missing one. If the user can't create the token
(no permission, page unreachable), stop and suggest asking whoever
manages the Atlassian accounts.
## Step 2 — Save, then verify
1. Create `~/.config/gw-triage/` if missing. Write the netrc file with
the file-writing tool:
machine <host>
login <email>
password <token>
Then `chmod 600 ~/.config/gw-triage/netrc`.
2. Run the verification call.
- `200` → Step 3.
- `401`/`403` → wrong email or token (a common cause: copied with a
trailing space or truncated). Ask the user to re-copy and
re-paste, rewrite the file, verify again; after the third failed
verification overall, delete the netrc file, stop, and suggest
creating a fresh token.
- Anything else (timeout, DNS) → network problem, not credentials:
report it and stop. Leave the netrc in place — it may verify fine
later.
## Step 3 — Clean up legacy stores
1. `~/.claude/settings.json`: if it exists and has `env.JIRA_EMAIL` /
`env.JIRA_API_TOKEN`, offer (Italian) to remove those two keys —
with the file tools (Read + Edit), never shell text-mangling, and
preserving every other key. If the file is invalid JSON, don't
touch it; just tell the user it should be cleaned up by hand.
2. Shell profiles: run
`fish -c 'set -U' 2>/dev/null | grep -i jira` and
`grep -l JIRA_API_TOKEN ~/.config/fish/config.fish ~/.config/fish/conf.d/*.fish ~/.zshrc ~/.bashrc ~/.zprofile ~/.profile 2>/dev/null`.
If anything turns up, tell the user (Italian) to remove it so it
can't shadow the netrc (fish: `set -e JIRA_EMAIL; set -e
JIRA_API_TOKEN`; altrimenti togliere gli `export` dal file
indicato).
## Step 4 — Report
In Italian: token verificato e salvato in `~/.config/gw-triage/netrc`.
Vale da subito, anche nelle sessioni già aperte. Per sostituirlo o dopo
una revoca basta rilanciare il setup: `/gw-triage:setup` su Claude
Code, `$setup` su Codex.
````
- [ ] **Step 2: Verify the file**
Run:
```bash
head -4 skills/setup/SKILL.md
grep -c 'netrc-file' skills/setup/SKILL.md
grep -n 'settings.json' skills/setup/SKILL.md
```
Expected: frontmatter intact with `name: setup`; `netrc-file` appears ≥1 time; `settings.json` appears only in migration/cleanup contexts (Step 0.2 and Step 3.1), never as the store.
- [ ] **Step 3: Commit**
```bash
git add skills/setup/SKILL.md
git commit -m "feat(setup): store credentials in shared netrc, migrate legacy env vars"
```
---
### Task 3: Rewrite `skills/triage/SKILL.md` with MCP/REST dual mode
**Files:**
- Modify: `skills/triage/SKILL.md` (full rewrite; frontmatter `name` unchanged)
**Interfaces:**
- Consumes: `~/.config/gw-triage/netrc` (Task 2 format) for REST mode and attachments.
- Produces: nothing consumed by other tasks; README (Task 5) references `$triage` invocation on Codex.
- [ ] **Step 1: Replace the file content**
Write `skills/triage/SKILL.md` with exactly:
````markdown
---
name: triage
description: Use when converting a bug report or feature request — a screenshot and/or a short message, typically forwarded from the company Telegram chat — into a Jira issue routed to the right developer. Triggers on /gw-triage:triage, $triage, "crea una issue da questo", "segnala questo bug", or a pasted/dropped Telegram report with intent to track it.
---
# Triage — da segnalazione a issue Jira
You convert an informal report (screenshot + short message) into a
well-formed Jira issue assigned to the right developer.
**All interaction with the user happens in Italian.** This file is
English for precision; never quote it to the user.
## Environment
- **Root**: `${CLAUDE_PLUGIN_ROOT}` if that variable is set; otherwise
the real path of this skill's own directory (resolve symlinks, e.g.
with `realpath`), two levels up. `config/` and `knowledge/` below
are relative to this root.
- **Netrc**: `~/.config/gw-triage/netrc` — Jira credentials, written
by the `setup` skill.
- **Mode** — how Jira is reached:
- **MCP mode** (Claude Code): the Atlassian MCP tools (prefix
`mcp__plugin_atlassian_atlassian__`) are available. If they are
deferred, load them in ONE ToolSearch call before Step 0:
`select:mcp__plugin_atlassian_atlassian__getAccessibleAtlassianResources,mcp__plugin_atlassian_atlassian__searchJiraIssuesUsingJql,mcp__plugin_atlassian_atlassian__createJiraIssue,mcp__plugin_atlassian_atlassian__addCommentToJiraIssue`
- **REST mode** (Codex, or any platform without those tools): curl
against the Jira Cloud REST API v2, authenticated with
`--netrc-file ~/.config/gw-triage/netrc`. `<site>` in the URLs
below is the `site` value from routing.json; `cloudId` is not
used in REST mode.
Exception: on Claude Code (recognizable by `CLAUDE_PLUGIN_ROOT`
being set), MCP is the intended path — if the tools are missing, do
NOT fall back to REST; stop with the install guide in Step 0.
For REST calls that send a JSON body, write the body to a temp file
first (`mktemp`) and pass it with `-d @<file>` — never inline JSON
with user text on the command line.
## Step 0 — Preflight
**MCP mode**
1. Call `getAccessibleAtlassianResources`. If the tool is missing or
returns an authentication error, STOP and print this guide in
Italian, then end the turn:
- installa il plugin Atlassian: `/plugin install atlassian@claude-plugins-official`
- esegui `/mcp`, seleziona `atlassian` e completa il login nel browser con l'account aziendale
- poi rilancia `/gw-triage:triage`
2. Attachment credentials:
`test -r ~/.config/gw-triage/netrc && echo netrc || (test -n "$JIRA_EMAIL" && test -n "$JIRA_API_TOKEN" && echo env || echo missing)`.
Remember the answer for Step 7. If `missing`, tell the user
(Italian) the screenshot cannot be attached automatically and that
`/gw-triage:setup` configures it in a couple of minutes. Say it
once and proceed.
**REST mode** — the netrc is required; it is the only transport.
1. `test -r ~/.config/gw-triage/netrc && echo ok || echo missing` —
if `missing`, STOP and print in Italian: serve il token API Jira;
esegui `$setup` e poi rilancia `$triage`.
2. Verify:
curl -s -o /dev/null -w "%{http_code}" \
--netrc-file ~/.config/gw-triage/netrc \
<site>/rest/api/2/myself
Anything but `200` → STOP (Italian): token scaduto o revocato,
rilancia `$setup`.
## Step 1 — Input
Expect a short message (usually Italian) and optionally a screenshot.
- Screenshot given as a file path (dragged into the prompt): Read it
for analysis and keep the path for Step 7.
- Pasted image (no path): analyze it; warn (Italian) that the
attachment will be skipped — it can be dragged into Jira manually.
- No screenshot: proceed on the text alone.
- Neither message nor screenshot: ask (Italian) for at least one.
## Step 2 — Load routing and knowledge
Read `<root>/config/routing.json` and every `.md` file in
`<root>/knowledge/` except `README.md`.
## Step 3 — Classify
Decide, using the knowledge profiles (error fingerprints, symptom
heuristics, glossaries, "not mine" sections):
- **type**: `Bug` (something broken) or `Task` (feature request /
change / improvement)
- **area**: exactly one key from `routing.json` `areas`.
Platform rules for app issues: visible Android UI or device →
`app-android`; visible iOS UI or device → `app-ios`; app issue with no
platform signal → `app-shared`.
If genuinely uncertain between two areas, ask the user ONE targeted
question in Italian (e.g. "Succede solo su iOS o anche su Android?").
Never more than one question; otherwise decide and state the assumption
in the draft.
If no knowledge profile covers the symptoms, classify using the
routing.json area list alone and state the lower confidence explicitly
in the draft.
## Step 4 — Duplicate check
Extract 24 distinctive keywords (include Italian and English variants
of domain terms). Search with JQL
`project = <projectKey> AND text ~ "<keywords>" AND statusCategory != Done ORDER BY created DESC`
(maxResults 10):
- MCP mode: `searchJiraIssuesUsingJql`.
- REST mode (note: search is the one call NOT on v2 — Atlassian
removed `/rest/api/2/search` in 2025; `/rest/api/3/search/jql` is
its replacement):
curl -s --netrc-file ~/.config/gw-triage/netrc -G \
--data-urlencode 'jql=<the JQL above>' \
--data-urlencode 'maxResults=10' \
--data-urlencode 'fields=summary,status,issuetype' \
"<site>/rest/api/3/search/jql"
Judge similarity by symptom, not wording.
If a likely duplicate exists: show it (key, title, status) and ask
(Italian) whether to comment on it instead of creating a new issue.
If yes, add a comment with the new report's details (and note the
screenshot can't be attached to a comment automatically), report the
link, stop:
- MCP mode: `addCommentToJiraIssue`.
- REST mode — write `{"body": "<comment text>"}` to a temp file, then:
curl -s -o /tmp/gw-triage-comment.json -w "%{http_code}" \
--netrc-file ~/.config/gw-triage/netrc \
-H "Content-Type: application/json" \
-X POST -d @<temp-file> \
"<site>/rest/api/2/issue/<KEY>/comment"
Success = HTTP 201.
## Step 5 — Draft (Italian)
Build and present:
- **Titolo**: concise imperative, e.g. "Correggere overflow nella
schermata prenotazioni su Android".
- **Descrizione** with sections:
- *Contesto* — source of the report (chat Telegram, date, reporter
if known)
- *Passi per riprodurre* — inferred from screenshot/message; mark
inferred steps explicitly ("(dedotto dallo screenshot)")
- *Comportamento atteso / osservato*
- *Screenshot* — one line describing what it shows
- **Tipo**: Bug or Task. **Epic**: from routing area. **Assegnatario**:
from routing area.
Show the complete draft and ask ONE confirmation (sì / correggi …).
Apply corrections; re-confirm only if the area changed (it changes
epic and assignee).
## Step 6 — Create
- MCP mode: call `createJiraIssue` with `cloudId`, `projectKey`,
`issueTypeName` (`Bug` or `Task`), `summary`, `description`, the
area's `assignee.accountId`, and
`additional_fields: {"parent": {"key": "<area epic>"}}`.
- REST mode — write this JSON to a temp file (description as plain
text; Jira wiki markup like `h3.` headings and `*bold*` is allowed):
{
"fields": {
"project": {"key": "<projectKey>"},
"issuetype": {"name": "<Bug|Task>"},
"summary": "<titolo>",
"description": "<descrizione>",
"assignee": {"accountId": "<area accountId>"},
"parent": {"key": "<area epic>"}
}
}
Then:
curl -s -o /tmp/gw-triage-create.json -w "%{http_code}" \
--netrc-file ~/.config/gw-triage/netrc \
-H "Content-Type: application/json" \
-X POST -d @<temp-file> \
"<site>/rest/api/2/issue"
Success = HTTP 201; the issue key is in the response file.
If the call fails, report the raw error with a one-line Italian
summary and stop — nothing partial to clean up (the attachment step
only runs after successful creation).
## Step 7 — Attach screenshot
Only if Step 0 found credentials (netrc or legacy env) AND the
screenshot is a file path:
curl -s -o /tmp/gw-triage-attach.json -w "%{http_code}" -X POST \
-H "X-Atlassian-Token: no-check" \
--netrc-file ~/.config/gw-triage/netrc \
-F "file=@<screenshot-path>" \
"<site>/rest/api/3/issue/<ISSUE-KEY>/attachments"
If Step 0 answered `env` (legacy install, no netrc), replace the
`--netrc-file` line with `-u "$JIRA_EMAIL:$JIRA_API_TOKEN"`, leaving
the `$` references unexpanded for the shell — never substitute the
values yourself.
Success = HTTP 200. Any failure is non-fatal: tell the user (Italian)
to drag the image into the Jira issue manually.
## Step 8 — Report
Print in Italian: issue key with link `<site>/browse/<KEY>`, type,
epic, assignee, and whether the screenshot was attached.
````
- [ ] **Step 2: Verify the file**
Run:
```bash
head -4 skills/triage/SKILL.md
grep -c 'REST mode' skills/triage/SKILL.md
grep -n 'CLAUDE_PLUGIN_ROOT' skills/triage/SKILL.md
grep -n 'rest/api/3' skills/triage/SKILL.md
```
Expected: frontmatter intact with `name: triage`; `REST mode` appears in Environment and Steps 0/4/6; `CLAUDE_PLUGIN_ROOT` appears only in the Environment root/mode rules (not as a hardcoded path elsewhere); the only v3 URLs are the attachments endpoint and `search/jql`.
- [ ] **Step 3: Commit**
```bash
git add skills/triage/SKILL.md
git commit -m "feat(triage): dual MCP/REST mode with shared netrc credentials"
```
---
### Task 4: Update `skills/map-repo/SKILL.md`
**Files:**
- Modify: `skills/map-repo/SKILL.md` (three targeted edits)
**Interfaces:**
- Consumes: root-resolution convention from Tasks 23 (same preamble wording).
- [ ] **Step 1: Update frontmatter description**
Replace:
```
description: Use when generating or refreshing a codebase's triage profile for the gw-triage plugin — run from inside the repo to map. Triggers on /map-repo, "mappa questo repo", "aggiorna il profilo di triage".
```
with:
```
description: Use when generating or refreshing a codebase's triage profile for the gw-triage plugin — run from inside the repo to map. Triggers on /gw-triage:map-repo, $map-repo, "mappa questo repo", "aggiorna il profilo di triage".
```
- [ ] **Step 2: Add the Environment section and fix root references**
After the paragraph ending "(it is read by the triage model, not by humans).", insert:
```markdown
## Environment
**Root**: `${CLAUDE_PLUGIN_ROOT}` if that variable is set; otherwise
the real path of this skill's own directory (resolve symlinks, e.g.
with `realpath`), two levels up. Paths below marked `<root>` are
relative to it.
```
Then replace `${CLAUDE_PLUGIN_ROOT}/knowledge/README.md` with `<root>/knowledge/README.md` (Step 2) and `${CLAUDE_PLUGIN_ROOT}` with `<root>` in Step 4's remote-URL instruction.
- [ ] **Step 3: Make the survey subagent optional**
Replace:
```
Dispatch ONE exploration subagent with this prompt, filling <repo-path>:
```
with:
```
If the platform supports dispatching subagents, dispatch ONE
exploration subagent with the prompt below, filling <repo-path>;
otherwise perform the same survey yourself, covering all six points
before writing anything:
```
- [ ] **Step 4: Mention the Codex update path in Step 4 of the skill**
Replace:
```
4. Tell the user (Italian) that teammates receive the update with
`/plugin marketplace update gw-triage`.
```
with:
```
4. Tell the user (Italian) that teammates receive the update with
`/plugin marketplace update gw-triage` on Claude Code, or with
`git pull` in their gw-triage clone on Codex.
```
- [ ] **Step 5: Verify and commit**
```bash
grep -c 'CLAUDE_PLUGIN_ROOT' skills/map-repo/SKILL.md
grep -n '<root>' skills/map-repo/SKILL.md
git add skills/map-repo/SKILL.md
git commit -m "feat(map-repo): platform-neutral root resolution and survey"
```
Expected: `CLAUDE_PLUGIN_ROOT` count is 1 (the Environment section only); `<root>` appears in Steps 2 and 4.
---
### Task 5: README + version bump
**Files:**
- Modify: `README.md`
- Modify: `.claude-plugin/plugin.json` (version `0.2.0` → `0.3.0`)
**Interfaces:**
- Consumes: `./install-codex.sh` (Task 1), netrc store (Task 2), `$triage`/`$setup` invocations (Tasks 23).
- [ ] **Step 1: Restructure the installation section**
Replace the `## Installazione (una volta sola)` section with:
```markdown
## Installazione (una volta sola)
### Claude Code
1. **Plugin Atlassian** — in Claude Code:
`/plugin install atlassian@claude-plugins-official`
2. **Login Atlassian** — esegui `/mcp`, seleziona `atlassian` e completa
il login nel browser con l'account aziendale. Verifica che risulti
*connected*.
3. **Installa gw-triage**:
`/plugin marketplace add https://git.growingway.com/giuse/gw-triage.git`
`/plugin install gw-triage`
4. **Token API** (per allegare gli screenshot — facoltativo ma
consigliato): esegui `/gw-triage:setup` e segui le istruzioni.
### Codex CLI
1. Clona il repo dove preferisci:
`git clone https://git.growingway.com/giuse/gw-triage.git`
2. Dalla cartella clonata esegui `./install-codex.sh` — crea i link
alle skill in `~/.agents/skills/`. Nota: le skill si chiamano
`triage`, `setup` e `map-repo`; se hai già altre skill con questi
nomi entrano in conflitto.
3. **Token API** (qui obbligatorio — su Codex tutte le chiamate Jira
lo usano): invoca `$setup` e segui le istruzioni.
Per aggiornare: `git pull` nella cartella clonata (i link restano
validi). Su Claude Code: `/plugin marketplace update gw-triage`.
```
- [ ] **Step 2: Update the token section**
Replace the `## Token API Jira` section with:
```markdown
## Token API Jira
Su Claude Code serve solo ad allegare gli screenshot alle issue (le
altre operazioni passano dall'MCP Atlassian): senza token tutto
funziona lo stesso, viene saltato solo l'allegato. Su Codex invece è
obbligatorio: tutte le chiamate Jira lo usano.
Esegui il setup (`/gw-triage:setup` su Claude Code, `$setup` su
Codex): ti guida nella creazione del token dalla pagina Atlassian, te
lo chiede, lo verifica e lo salva in `~/.config/gw-triage/netrc`
(valido da subito, senza riavviare nulla). Se avevi già configurato il
token in `~/.claude/settings.json`, il setup lo migra da solo.
⚠️ Il token agisce a tuo nome su Jira: non condividerlo. Se trapela,
revocalo da <https://id.atlassian.com/manage-profile/security/api-tokens>.
Quando scade: su Claude Code `/gw-triage:triage` continua a funzionare
(salta solo l'allegato), su Codex si ferma e ti rimanda al setup.
Rilancia il setup per sostituirlo.
```
- [ ] **Step 3: Update daily use and troubleshooting**
In `## Uso quotidiano`, change step 1 to mention both invocations:
```markdown
1. Allega uno screenshot (**trascina il file nel prompt**, così può
essere allegato alla issue) e/o scrivi una breve descrizione del
problema, sufficiente a identificarlo, poi invoca
`/gw-triage:triage` (Claude Code) o `$triage` (Codex).
```
In `## Aggiornare la conoscenza dei repo`, replace the closing sentence
about updates with:
```markdown
il profilo aggiornato viene pushato qui e gli altri lo ricevono con
`/plugin marketplace update gw-triage` (Claude Code) o `git pull`
nella cartella clonata (Codex).
```
In `## Problemi comuni`, replace the "Allegato saltato" entry and add
one Codex entry:
```markdown
- **"MCP Atlassian non disponibile"** → passi 12 dell'installazione
Claude Code.
- **"Allegato saltato"** → esegui il setup (token mancante, scaduto o
revocato).
- **Su Codex le skill non compaiono** → riesegui `./install-codex.sh`
dalla cartella clonata e controlla i link in `~/.agents/skills/`.
- **La issue finisce nell'epic sbagliata** → correggi in Jira e apri
una issue su questo repo per aggiustare `config/routing.json` o il
profilo in `knowledge/`.
```
- [ ] **Step 4: Bump the plugin version**
In `.claude-plugin/plugin.json`, change `"version": "0.2.0"` to `"version": "0.3.0"`.
- [ ] **Step 5: Verify and commit**
```bash
grep -n 'Codex' README.md | head -20
python3 -c "import json; print(json.load(open('.claude-plugin/plugin.json'))['version'])"
git add README.md .claude-plugin/plugin.json
git commit -m "docs: Codex CLI install/usage instructions; bump to 0.3.0"
```
Expected: Codex sections present; version prints `0.3.0`.
---
### Task 6: Live verification (needs the user's Jira credentials)
**Files:** none (verification only).
This task exercises the REST path for real. It creates one throwaway
issue in the OA project — get the user's OK before running, and delete
the issue afterwards.
- [ ] **Step 1: Netrc present**
If `~/.config/gw-triage/netrc` doesn't exist, run the setup skill flow
first (or migrate from `~/.claude/settings.json` per setup Step 0.2).
- [ ] **Step 2: Auth check**
```bash
curl -s -o /dev/null -w "%{http_code}" --netrc-file ~/.config/gw-triage/netrc https://growingway.atlassian.net/rest/api/2/myself
```
Expected: `200`.
- [ ] **Step 3: JQL search**
```bash
curl -s --netrc-file ~/.config/gw-triage/netrc -G \
--data-urlencode 'jql=project = OA ORDER BY created DESC' \
--data-urlencode 'maxResults=3' \
--data-urlencode 'fields=summary,status' \
"https://growingway.atlassian.net/rest/api/3/search/jql" | head -c 400
```
Expected: JSON with `issues` array.
- [ ] **Step 4: Create + comment + attach + delete a throwaway issue**
Create (body via temp file, per the skill):
```bash
printf '%s' '{"fields":{"project":{"key":"OA"},"issuetype":{"name":"Task"},"summary":"[test gw-triage] verifica REST — da cancellare","description":"Test automatico del percorso REST di gw-triage. Cancellare."}}' > /tmp/gw-test-create.json
curl -s --netrc-file ~/.config/gw-triage/netrc -H "Content-Type: application/json" -X POST -d @/tmp/gw-test-create.json "https://growingway.atlassian.net/rest/api/2/issue"
```
Expected: JSON with a `key` (e.g. `OA-123`). With that KEY:
```bash
printf '%s' '{"body":"commento di test"}' > /tmp/gw-test-comment.json
curl -s -o /dev/null -w "%{http_code}" --netrc-file ~/.config/gw-triage/netrc -H "Content-Type: application/json" -X POST -d @/tmp/gw-test-comment.json "https://growingway.atlassian.net/rest/api/2/issue/<KEY>/comment"
```
Expected: `201`. Attachment (any small local image or text file):
```bash
curl -s -o /dev/null -w "%{http_code}" -X POST -H "X-Atlassian-Token: no-check" --netrc-file ~/.config/gw-triage/netrc -F "file=@<some-file>" "https://growingway.atlassian.net/rest/api/3/issue/<KEY>/attachments"
```
Expected: `200`. Then delete:
```bash
curl -s -o /dev/null -w "%{http_code}" --netrc-file ~/.config/gw-triage/netrc -X DELETE "https://growingway.atlassian.net/rest/api/2/issue/<KEY>"
```
Expected: `204`. Clean up `/tmp/gw-test-*.json`.
- [ ] **Step 5: Codex smoke test (user-run)**
Ask the user to run, in a Codex session: `$setup` (should report the
existing token works) and `$triage` with a sample message, stopping at
the draft confirmation with "correggi: annulla". Confirm the skills
were discovered and REST preflight passed.
- [ ] **Step 6: Claude Code regression (user-run)**
`/gw-triage:triage` with a sample report in a Claude Code session:
MCP mode preflight, netrc detected for attachments. Cancel at the
draft. Then push everything:
```bash
git push
```

20
install-codex.sh Executable file
View File

@@ -0,0 +1,20 @@
#!/bin/sh
# Install the gw-triage skills for OpenAI Codex CLI by symlinking them
# into ~/.agents/skills. Safe to re-run; updates arrive via `git pull`
# in this clone (symlinks keep pointing at the updated files).
set -eu
repo_dir=$(CDPATH= cd -- "$(dirname -- "$0")" && pwd -P)
dest="${HOME}/.agents/skills"
mkdir -p "$dest"
for skill in triage setup map-repo; do
if [ -e "$dest/$skill" ] && [ ! -L "$dest/$skill" ]; then
echo "errore: $dest/$skill esiste già e non è un link simbolico — rimuovilo e rilancia" >&2
exit 1
fi
ln -sfn "$repo_dir/skills/$skill" "$dest/$skill"
echo "linked $dest/$skill -> $repo_dir/skills/$skill"
done
echo "Fatto. Per aggiornare in futuro: git -C \"$repo_dir\" pull"

View File

@@ -1,6 +1,6 @@
---
name: map-repo
description: Use when generating or refreshing a codebase's triage profile for the gw-triage plugin — run from inside the repo to map. Triggers on /map-repo, "mappa questo repo", "aggiorna il profilo di triage".
description: Use when generating or refreshing a codebase's triage profile for the gw-triage plugin — run from inside the repo to map. Triggers on /gw-triage:map-repo, $map-repo, "mappa questo repo", "aggiorna il profilo di triage".
---
# Map-repo — profilo di triage del codebase
@@ -12,6 +12,13 @@ and guide them to publish it to the gw-triage plugin repo.
profile is written in English (it is read by the triage model, not by
humans).
## Environment
**Root**: `${CLAUDE_PLUGIN_ROOT}` if that variable is set; otherwise
the real path of this skill's own directory (resolve symlinks, e.g.
with `realpath`), two levels up. Paths below marked `<root>` are
relative to it.
## Step 1 — Identify the repo
- `git rev-parse --show-toplevel` — if not a git repo, ask (Italian)
@@ -20,8 +27,11 @@ humans).
## Step 2 — Survey
Read `${CLAUDE_PLUGIN_ROOT}/knowledge/README.md` (the profile format).
Dispatch ONE exploration subagent with this prompt, filling <repo-path>:
Read `<root>/knowledge/README.md` (the profile format).
If the platform supports dispatching subagents, dispatch ONE
exploration subagent with the prompt below, filling <repo-path>;
otherwise perform the same survey yourself, covering all six points
before writing anything:
> Survey the codebase at <repo-path> to build a triage profile.
> Report back, with file evidence: (1) what the system does — main
@@ -48,7 +58,7 @@ Write it to a temporary location first (the session scratchpad or
Ask (Italian) for the local path of the user's gw-triage checkout;
offer to `git clone <plugin-repo-url>` if they don't have one (read
the URL from `git remote get-url origin` run in
`${CLAUDE_PLUGIN_ROOT}` if available, otherwise ask).
`<root>` if available, otherwise ask).
With the user's confirmation, in the checkout:
1. Copy the profile to `knowledge/<repo-name>.md` (overwrite if
@@ -59,4 +69,5 @@ With the user's confirmation, in the checkout:
then `git commit -m "knowledge: add/update <repo-name> profile"`
— ask before committing, and ask again before `git push`.
4. Tell the user (Italian) that teammates receive the update with
`/plugin marketplace update gw-triage`.
`/plugin marketplace update gw-triage` on Claude Code, or with
`git pull` in their gw-triage clone on Codex.

View File

@@ -1,60 +1,83 @@
---
name: setup
description: Use when configuring the Jira API credentials for gw-triage — first-time setup, an "allegato saltato" warning from triage, missing or expired JIRA_EMAIL/JIRA_API_TOKEN, or replacing a revoked token. Triggers on /gw-triage:setup, "configura il token", "gli allegati non funzionano".
description: Use when configuring the Jira API credentials for gw-triage — first-time setup, an "allegato saltato" warning from triage, missing or expired credentials, or replacing a revoked token. Triggers on /gw-triage:setup, $setup, "configura il token", "gli allegati non funzionano".
---
# Setup — token API Jira guidato
You guide the user through creating a Jira API token and storing it so
the `triage` skill can attach screenshots to issues.
You guide the user through creating a Jira API token and storing it in
the gw-triage netrc file. The `triage` skill reads that file for its
REST calls: screenshot attachments on every platform, plus search /
create / comment when running under Codex.
**All interaction with the user happens in Italian.** This file is
English for precision; never quote it to the user.
The only consumer of the token is the `triage` skill (its curl
attachment call), which runs inside Claude Code. Credentials therefore
go in the `env` block of `~/.claude/settings.json` — Claude Code
injects them into every session, regardless of the user's shell. Never
touch shell profiles.
## Environment
- **Root**: `${CLAUDE_PLUGIN_ROOT}` if that variable is set; otherwise
the real path of this skill's own directory (resolve symlinks, e.g.
with `realpath`), two levels up.
- **Store**: `~/.config/gw-triage/netrc`, mode 600. curl reads it at
call time on every platform, so changes take effect immediately — no
session restart, no shell configuration.
- **Host**: the `site` value in `<root>/config/routing.json` without
the scheme (e.g. `growingway.atlassian.net`).
**Keep the token out of replies and displayed commands.** Refer to it
as "il token" and never repeat its value. Never inline a literal token
on a shell command line — it ends up in the transcript and the process
list. Shell variables may be passed as unexpanded `$VAR` references;
literal values (pasted or read from a file) go through the temp netrc
file described in Step 0.3.
list. Write credentials into the netrc file with the file-writing
tool — or, for values that live only in session env vars, via shell
redirection with unexpanded `$VAR` references — then let curl read
them via `--netrc-file`.
The verification call used throughout:
curl -s -o /dev/null -w "%{http_code}" \
--netrc-file ~/.config/gw-triage/netrc \
https://<host>/rest/api/2/myself
## Step 0 — Check existing configuration
1. Run `test -n "$JIRA_EMAIL" && test -n "$JIRA_API_TOKEN" && echo session || echo unset`.
2. Read `~/.claude/settings.json` (if it exists) and note whether
`env.JIRA_EMAIL` / `env.JIRA_API_TOKEN` are present.
3. If credentials exist in either place, verify them. The check call is
curl -s -o /dev/null -w "%{http_code}" \
<credentials> \
https://growingway.atlassian.net/rest/api/3/myself
(host = the `site` in `${CLAUDE_PLUGIN_ROOT}/config/routing.json`,
without the scheme). For `<credentials>`:
- session env vars set → `-u "$JIRA_EMAIL:$JIRA_API_TOKEN"`, with the
`$` references left unexpanded for the shell to fill in — never
substitute the values yourself.
- literal values (from settings.json or a paste) → use the Write
tool to create a netrc file in the session scratchpad directory:
machine growingway.atlassian.net
login <email>
password <token>
`chmod 600` it and pass `--netrc-file <path>` instead of `-u`.
Delete this file before the skill ends, whatever the outcome.
Result:
1. If `~/.config/gw-triage/netrc` exists and is readable, run the
verification call.
- `200` → tell the user (Italian) the token already works and ask
whether they want to replace it anyway. If not, stop.
- anything else → tell them the stored token no longer works
(probably expired or revoked) and continue.
- `401`/`403` → tell them the stored token no longer works
(probably expired or revoked) and continue to Step 1.
- anything else (timeout, DNS) → network problem, not credentials:
report it (Italian) and stop.
2. Otherwise look for legacy credentials, in order:
- session env: `test -n "$JIRA_EMAIL" && test -n "$JIRA_API_TOKEN" && echo session || echo unset`
- `~/.claude/settings.json` (if it exists): `env.JIRA_EMAIL` /
`env.JIRA_API_TOKEN`.
If found in either place: write them to the netrc (Step 2 format,
chmod 600) and run the verification call.
**Important — how to write the netrc depends on where the values
came from:**
- Values read from `~/.claude/settings.json` are literals you
already hold: write the netrc with the file-writing tool as usual.
- Session-env credentials must never be echoed or expanded by you:
write the file via shell redirection with unexpanded references,
e.g.
printf 'machine <host>\nlogin %s\npassword %s\n' \
"$JIRA_EMAIL" "$JIRA_API_TOKEN" > ~/.config/gw-triage/netrc
chmod 600 ~/.config/gw-triage/netrc
After writing, run the verification call.
- `200` → tell the user (Italian) the existing credentials were
migrated to the new store and work immediately; then do Step 3
(clean up legacy stores) and Step 4. Done — skip token creation.
- `401`/`403` → delete the netrc just written, tell them the old
token no longer works, continue to Step 1.
- anything else (timeout, DNS) → network problem, not credentials:
report it (Italian) and stop, leaving the netrc in place — it may
verify fine later.
3. Nothing found → first-time setup, continue to Step 1.
## Step 1 — Token creation (user, in the browser)
@@ -67,52 +90,53 @@ Print in Italian, compactly:
3. Incolla qui email aziendale e token (vanno bene anche su due righe).
Add one line: il token verrà salvato in chiaro in
`~/.claude/settings.json` sul suo computer, quindi non condividere né il
file né questa conversazione.
`~/.config/gw-triage/netrc` sul suo computer, quindi non condividere né
il file né questa conversazione.
End the turn and wait. If the reply contains only one of the two
values, ask for the missing one. If the user can't create the token
(no permission, page unreachable), stop and suggest asking whoever
manages the Atlassian accounts.
## Step 2 — Verify before saving
## Step 2 — Save, then verify
Run the Step 0.3 check with the pasted values — literals, so via the
temp netrc file, never `-u` on the command line.
1. Create `~/.config/gw-triage/` if missing. Write the netrc file with
the file-writing tool:
- `200` → proceed to Step 3.
- `401`/`403` → wrong email or token (a common cause: copied with a
trailing space or truncated). Ask the user to re-copy and re-paste,
then verify again; stop after the third failed verification overall
and suggest creating a fresh token.
- Anything else (timeout, DNS) → network problem, not credentials:
report it and stop; the pasted token stays valid for a later retry.
machine <host>
login <email>
password <token>
## Step 3 — Save to settings.json
Then `chmod 600 ~/.config/gw-triage/netrc`.
2. Run the verification call.
- `200` → Step 3.
- `401`/`403` → wrong email or token (a common cause: copied with a
trailing space or truncated). Ask the user to re-copy and
re-paste, rewrite the file, verify again; after the third failed
verification overall, delete the netrc file, stop, and suggest
creating a fresh token.
- Anything else (timeout, DNS) → network problem, not credentials:
report it and stop. Leave the netrc in place — it may verify fine
later.
Update `~/.claude/settings.json` with Read + Edit/Write (never shell
text-mangling):
## Step 3 — Clean up legacy stores
- File missing → create it containing only
`{"env": {"JIRA_EMAIL": "<email>", "JIRA_API_TOKEN": "<token>"}}`.
- Valid JSON → add or overwrite the two keys inside the existing `env`
object (create the object if absent). Preserve every other key
untouched.
- Invalid JSON → do NOT overwrite; show the user the parse error and
stop.
Leftover check: old installs configured the shell profile instead. Run
`fish -c 'set -U' 2>/dev/null | grep -i jira` and
`grep -l JIRA_API_TOKEN ~/.config/fish/config.fish ~/.config/fish/conf.d/*.fish ~/.zshrc ~/.bashrc ~/.zprofile ~/.profile 2>/dev/null`.
If anything turns up, tell the user (Italian) to remove it so it can't
shadow the new token (fish: `set -e JIRA_EMAIL; set -e JIRA_API_TOKEN`;
altrimenti togliere gli `export` dal file indicato).
1. `~/.claude/settings.json`: if it exists and has `env.JIRA_EMAIL` /
`env.JIRA_API_TOKEN`, offer (Italian) to remove those two keys —
with the file tools (Read + Edit), never shell text-mangling, and
preserving every other key. If the file is invalid JSON, don't
touch it; just tell the user it should be cleaned up by hand.
2. Shell profiles: run
`fish -c 'set -U' 2>/dev/null | grep -i jira` and
`grep -l JIRA_API_TOKEN ~/.config/fish/config.fish ~/.config/fish/conf.d/*.fish ~/.zshrc ~/.bashrc ~/.zprofile ~/.profile 2>/dev/null`.
If anything turns up, tell the user (Italian) to remove it so it
can't shadow the netrc (fish: `set -e JIRA_EMAIL; set -e
JIRA_API_TOKEN`; altrimenti togliere gli `export` dal file
indicato).
## Step 4 — Report
Delete the temp netrc file if one was created.
In Italian: token verificato e salvato. Vale dalle **prossime** sessioni
di Claude Code — quelle già aperte vanno riavviate prima che l'allegato
automatico funzioni. Per sostituirlo o dopo una revoca basta rilanciare
`/gw-triage:setup`.
In Italian: token verificato e salvato in `~/.config/gw-triage/netrc`.
Vale da subito, anche nelle sessioni già aperte. Per sostituirlo o dopo
una revoca basta rilanciare il setup: `/gw-triage:setup` su Claude
Code, `$setup` su Codex.

View File

@@ -1,6 +1,6 @@
---
name: triage
description: Use when converting a bug report or feature request — a screenshot and/or a short message, typically forwarded from the company Telegram chat — into a Jira issue routed to the right developer. Triggers on /gw-triage:triage, "crea una issue da questo", "segnala questo bug", or a pasted/dropped Telegram report with intent to track it.
description: Use when converting a bug report or feature request — a screenshot and/or a short message, typically forwarded from the company Telegram chat — into a Jira issue routed to the right developer. Triggers on /gw-triage:triage, $triage, "crea una issue da questo", "segnala questo bug", or a pasted/dropped Telegram report with intent to track it.
---
# Triage — da segnalazione a issue Jira
@@ -11,26 +11,65 @@ well-formed Jira issue assigned to the right developer.
**All interaction with the user happens in Italian.** This file is
English for precision; never quote it to the user.
The Atlassian MCP tools referenced below live under the
`mcp__plugin_atlassian_atlassian__` prefix. If they are deferred, load
them in ONE ToolSearch call before Step 0:
`select:mcp__plugin_atlassian_atlassian__getAccessibleAtlassianResources,mcp__plugin_atlassian_atlassian__searchJiraIssuesUsingJql,mcp__plugin_atlassian_atlassian__createJiraIssue,mcp__plugin_atlassian_atlassian__addCommentToJiraIssue`
## Environment
- **Root**: `${CLAUDE_PLUGIN_ROOT}` if that variable is set; otherwise
the real path of this skill's own directory (resolve symlinks, e.g.
with `realpath`), two levels up. `config/` and `knowledge/` below
are relative to this root.
- **Netrc**: `~/.config/gw-triage/netrc` — Jira credentials, written
by the `setup` skill.
- **Mode** — how Jira is reached:
- **MCP mode** (Claude Code): the Atlassian MCP tools (prefix
`mcp__plugin_atlassian_atlassian__`) are available. If they are
deferred, load them in ONE ToolSearch call before Step 0:
`select:mcp__plugin_atlassian_atlassian__getAccessibleAtlassianResources,mcp__plugin_atlassian_atlassian__searchJiraIssuesUsingJql,mcp__plugin_atlassian_atlassian__createJiraIssue,mcp__plugin_atlassian_atlassian__addCommentToJiraIssue`
- **REST mode** (Codex, or any platform without those tools): curl
against the Jira Cloud REST API v2, authenticated with
`--netrc-file ~/.config/gw-triage/netrc`. `<site>` in the URLs
below is the `site` value from routing.json; `cloudId` is not
used in REST mode.
Exception: on Claude Code (recognizable by `CLAUDE_PLUGIN_ROOT`
being set), MCP is the intended path — if the tools are missing, do
NOT fall back to REST; stop with the install guide in Step 0.
For REST calls that send a JSON body, write the body to a temp file
first (`mktemp`) and pass it with `-d @<file>` — never inline JSON
with user text on the command line.
## Step 0 — Preflight
**MCP mode**
1. Call `getAccessibleAtlassianResources`. If the tool is missing or
returns an authentication error, STOP and print this guide in
Italian, then end the turn:
- installa il plugin Atlassian: `/plugin install atlassian@claude-plugins-official`
- esegui `/mcp`, seleziona `atlassian` e completa il login nel browser con l'account aziendale
- poi rilancia `/gw-triage:triage`
2. Run `test -n "$JIRA_EMAIL" && test -n "$JIRA_API_TOKEN" && echo ok || echo missing`.
If `missing`: check whether `~/.claude/settings.json` has
`env.JIRA_EMAIL`/`env.JIRA_API_TOKEN`. If yes, the session predates
the config: tell the user (Italian) to restart Claude Code to enable
automatic attachments. If no, tell them the screenshot cannot be
attached automatically and that `/gw-triage:setup` configures it in
a couple of minutes. Either way, say it once and proceed.
2. Attachment credentials:
`test -r ~/.config/gw-triage/netrc && echo netrc || (test -n "$JIRA_EMAIL" && test -n "$JIRA_API_TOKEN" && echo env || echo missing)`.
Remember the answer for Step 7. If `missing`, tell the user
(Italian) the screenshot cannot be attached automatically and that
`/gw-triage:setup` configures it in a couple of minutes. Say it
once and proceed.
**REST mode** — the netrc is required; it is the only transport.
1. `test -r ~/.config/gw-triage/netrc && echo ok || echo missing`
if `missing`, STOP and print in Italian: serve il token API Jira;
esegui `$setup` e poi rilancia `$triage`.
2. Verify:
curl -s -o /dev/null -w "%{http_code}" \
--netrc-file ~/.config/gw-triage/netrc \
<site>/rest/api/2/myself
- `401`/`403` → STOP (Italian): token scaduto o revocato,
rilancia `$setup`.
- anything else → STOP (Italian): problema di rete verso Jira, non
di credenziali — riprova più tardi.
## Step 1 — Input
@@ -44,8 +83,8 @@ Expect a short message (usually Italian) and optionally a screenshot.
## Step 2 — Load routing and knowledge
Read `${CLAUDE_PLUGIN_ROOT}/config/routing.json` and every `.md` file
in `${CLAUDE_PLUGIN_ROOT}/knowledge/` except `README.md`.
Read `<root>/config/routing.json` and every `.md` file in
`<root>/knowledge/` except `README.md`.
## Step 3 — Classify
@@ -64,20 +103,46 @@ question in Italian (e.g. "Succede solo su iOS o anche su Android?").
Never more than one question; otherwise decide and state the assumption
in the draft.
If no knowledge profile covers the symptoms, classify using the routing.json area list alone and state the lower confidence explicitly in the draft.
If no knowledge profile covers the symptoms, classify using the
routing.json area list alone and state the lower confidence explicitly
in the draft.
## Step 4 — Duplicate check
Extract 24 distinctive keywords (include Italian and English variants
of domain terms). Call `searchJiraIssuesUsingJql` with:
of domain terms). Search with JQL
`project = <projectKey> AND text ~ "<keywords>" AND statusCategory != Done ORDER BY created DESC`
(maxResults 10). Judge similarity by symptom, not wording.
(maxResults 10):
- MCP mode: `searchJiraIssuesUsingJql`.
- REST mode (note: search is the one call NOT on v2 — Atlassian
removed `/rest/api/2/search` in 2025; `/rest/api/3/search/jql` is
its replacement):
curl -s --netrc-file ~/.config/gw-triage/netrc -G \
--data-urlencode 'jql=<the JQL above>' \
--data-urlencode 'maxResults=10' \
--data-urlencode 'fields=summary,status,issuetype' \
"<site>/rest/api/3/search/jql"
Judge similarity by symptom, not wording.
If a likely duplicate exists: show it (key, title, status) and ask
(Italian) whether to comment on it instead of creating a new issue.
If yes`addCommentToJiraIssue` with the new report's details (and
note the screenshot can't be attached to a comment automatically),
report the link, stop.
If yes, add a comment with the new report's details (and note the
screenshot can't be attached to a comment automatically), report the
link, stop:
- MCP mode: `addCommentToJiraIssue`.
- REST mode — write `{"body": "<comment text>"}` to a temp file, then:
curl -s -o /tmp/gw-triage-comment.json -w "%{http_code}" \
--netrc-file ~/.config/gw-triage/netrc \
-H "Content-Type: application/json" \
-X POST -d @<temp-file> \
"<site>/rest/api/2/issue/<KEY>/comment"
Success = HTTP 201.
## Step 5 — Draft (Italian)
@@ -100,9 +165,33 @@ epic and assignee).
## Step 6 — Create
Call `createJiraIssue` with: `cloudId`, `projectKey`, `issueTypeName`
(`Bug` or `Task`), `summary`, `description`, the area's
`assignee.accountId`, and `additional_fields: {"parent": {"key": "<area epic>"}}`.
- MCP mode: call `createJiraIssue` with `cloudId`, `projectKey`,
`issueTypeName` (`Bug` or `Task`), `summary`, `description`, the
area's `assignee.accountId`, and
`additional_fields: {"parent": {"key": "<area epic>"}}`.
- REST mode — write this JSON to a temp file (description as plain
text; Jira wiki markup like `h3.` headings and `*bold*` is allowed):
{
"fields": {
"project": {"key": "<projectKey>"},
"issuetype": {"name": "<Bug|Task>"},
"summary": "<titolo>",
"description": "<descrizione>",
"assignee": {"accountId": "<area accountId>"},
"parent": {"key": "<area epic>"}
}
}
Then:
curl -s -o /tmp/gw-triage-create.json -w "%{http_code}" \
--netrc-file ~/.config/gw-triage/netrc \
-H "Content-Type: application/json" \
-X POST -d @<temp-file> \
"<site>/rest/api/2/issue"
Success = HTTP 201; the issue key is in the response file.
If the call fails, report the raw error with a one-line Italian
summary and stop — nothing partial to clean up (the attachment step
@@ -110,17 +199,22 @@ only runs after successful creation).
## Step 7 — Attach screenshot
Only if Step 0 found the env vars AND the screenshot is a file path:
Only if Step 0 found credentials (netrc or legacy env) AND the
screenshot is a file path:
curl -s -o /tmp/gw-triage-attach.json -w "%{http_code}" -X POST \
-H "X-Atlassian-Token: no-check" \
-u "$JIRA_EMAIL:$JIRA_API_TOKEN" \
--netrc-file ~/.config/gw-triage/netrc \
-F "file=@<screenshot-path>" \
"<site>/rest/api/3/issue/<ISSUE-KEY>/attachments"
`<site>` comes from routing.json. Success = HTTP 200. Any failure is
non-fatal: tell the user (Italian) to drag the image into the Jira
issue manually.
If Step 0 answered `env` (legacy install, no netrc), replace the
`--netrc-file` line with `-u "$JIRA_EMAIL:$JIRA_API_TOKEN"`, leaving
the `$` references unexpanded for the shell — never substitute the
values yourself.
Success = HTTP 200. Any failure is non-fatal: tell the user (Italian)
to drag the image into the Jira issue manually.
## Step 8 — Report