Skip to content
Back to skills

Open Ticket

ASecurity

Turn an understood problem into a staged unit of work: one AskUserQuestion interview (slug, tracker GitHub / Jira / both / none), then the ticket directory, a Findings rollup from the lets-investigate ledger or what-we-know, the GitHub issue and/or Jira ticket (a draft file when the CLI is absent) with a checked tracker body, the branch, ticket.yml with derived model routing, and a validated ticket row in the state database. Ends by asking whether to plan now (game-plan), go straight to one-s...

  • 2 stars
  • 0 votes
  • 0 copies
  • 2 views
  • Added October 20, 2026
ai-agentspythonrustgobashgitdatabasesecuritydocumentation

Works with

  • cli
  • mcp

Security analysis

A100/100

Pro scans all 7 files and shows the line behind each finding

Scanned October 20, 2026

npx -y skills add rhawk117/rygentic-harness --skill open-ticket --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Open Ticket?

Add the live security badge to your README. It updates with every re-scan.

Security grade badge for Open Ticket
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/rhawk117-open-ticket/badge)](https://www.skillsdirectory.com/skills/rhawk117-open-ticket)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
SKILL.md
---
name: open-ticket
description: >-
  Turn an understood problem into a staged unit of work: one AskUserQuestion interview (slug,
  tracker GitHub / Jira / both / none), then the
  ticket directory, a Findings rollup from the lets-investigate ledger or what-we-know, the
  GitHub issue and/or Jira ticket (a draft file when the CLI is absent) with a checked tracker
  body, the branch, ticket.yml with derived model routing, and a validated ticket row in the
  state database. Ends by asking whether to plan now (game-plan), go straight to one-shot, or
  hand off (baton-pass). Not for starting the implementation
  itself (game-plan or one-shot), and not for handing off an existing ticket (baton-pass).
when_to_use: >-
  Use when triage is done: "cut a ticket for this", "open a ticket",
  "make a jira ticket under this epic", "turn this investigation into a ticket", "stage this
  for the next session", "get this ready to implement".
argument-hint: "[slug]"
allowed-tools:
  - AskUserQuestion
  - mcp__plugin_mightymodels_state__investigation
  - mcp__plugin_mightymodels_state__ticket
---

# open-ticket

Turn an understood problem into a unit of work that this session or a later one can pick up
cold. Everything durable lands in `ticket.yml`, the ticket's row in the state database, and the
tracker; what happens next is the user's call, asked at the end.

Read `references/ticket-schema.md` and `references/mightymodels-dir.md` before the first run
in a session; they are the contract this skill instantiates. State goes through the plugin's MCP
tools, called by full name: `mcp__plugin_mightymodels_state__ticket`, `..._investigation`.

Nothing under `.mightymodels/` is ever tracked by git. The state server adds `.mightymodels/`
to the repository's local exclude file when it starts, so a `git add -A` cannot ship briefs,
reports, or the database, which may carry raw command output.

## The interview

One `AskUserQuestion` dialog containing only the questions the conversation has not already
answered. Each
question carries two to four options, and the user can always type an answer of their own.
Answers already given are confirmed in the summary, not re-asked.

**Argument:** a slug for the new ticket, given when the skill was started: "$ARGUMENTS". Empty
quotes mean none was given. A slug given here is an answer already given to question 1.

1. **Name** this unit of work; options: a slug proposed from the triage target, a shorter one.
2. **Tracker**: GitHub issue, Jira ticket, both, or none.

The branch, the compaction and the scope of each anticipated task are not asked here: the
`ticket` `write` call (step D) leaves them out and asks the user itself.

When the tracker answer includes Jira, ask once, in chat, for the fields in one line: project
key, parent epic, issue type, story points, labels. Take whatever the user gives ("under
PLAT-40, story, 3 points" is a complete answer) and leave the rest unset; the CLI's defaults
and the project's own scheme fill them.

When the caller is baton-pass, the next step is already decided (hand off); do not ask it at
the end.

## The rollup

The tracker body is built from the triage, not from memory of it. Take the findings in this
order of preference:

1. **The investigation ledger.** Call `mcp__plugin_mightymodels_state__investigation` with
   action `knowns`:

   ```json
   {"request": {"action": "knowns", "investigation_id": "ID"}}
   ```

   With action `list` when the id is unknown:

   ```json
   {"request": {"action": "list"}}
   ```

   Rows marked `current` are findings. Rows marked `lead` were cited at an older HEAD: they go
   under Open questions as "unverified at HEAD", never under Findings, because the ramp would
   otherwise re-verify the wrong things.
2. **The final what-we-know output** in the conversation.
3. **Cited facts** scattered in the conversation.

From it:

- **Findings**: each current known with its citation, and each user decision. A claim without
  a citation goes under Open questions.
- **`context`** in ticket.yml: one to six lines carrying the knowns and decisions the next
  session cannot afford to lose, without `file:line` (locations rot; the tracker body keeps
  them and the ramp re-verifies them at HEAD).
- **`reference_urls`**: the ledger's resources, external documentation only.
- **`investigations`**: the investigation id, so the work unit links its ledger.

If no triage exists, say so and write the body from what the user has stated, with every
unverified claim marked as such. A ticket that presents guesses as findings sends the next
session confirming the wrong things.

## The actions

**A. Tracker body.** Fill `assets/tracker-body.md` from the rollup into
`.mightymodels/SLUG/issue-body.md`: Summary, Findings, Open questions, Acceptance as checkable
criteria where the triage established them, and a Security surface section only when the
change crosses a trust boundary, adds an input source, or touches authz or secrets (two to five
abuse cases phrased as candidate acceptance criteria; omit the section otherwise, since
inventing threats for a docs change teaches readers to skip the section that matters). Then:

```bash
python3 "${CLAUDE_SKILL_DIR}/scripts/humanize_tracker_body.py" fix .mightymodels/SLUG/issue-body.md
```

`fix` repairs dashes and filler openers itself and reports what still needs rewording (tell
words, uncited findings, placeholders, missing sections). Reword those, then run `check` until
it exits 0. No body reaches a tracker before it passes.

**B. Tracker.**

- *GitHub issue.* Discover the repo's conventions first: templates under
  `.github/ISSUE_TEMPLATE/`, labels in recent issues, title style from `gh issue list`. Create
  with `gh issue create --body-file .mightymodels/SLUG/issue-body.md`. If `gh` is unavailable
  or fails, keep the file and surface the exact command.
- *Jira ticket.* Check for the `jira` CLI with `command -v jira`. When present, discover the
  create command's flags from `jira issue create --help` rather than assuming them (custom
  fields such as story points are mapped per installation), then create with the fields the
  user gave and the checked body. When the CLI is absent or the create fails, write
  `.mightymodels/SLUG/jira-ticket.md` carrying the fields as a header block, the body, and the
  exact command, and say so in the summary.
- *Both.* Create the GitHub issue first, then the Jira ticket with the issue URL in its body,
  so the two link one way and the sprint's task list has one home (the GitHub issue).

**C. Branch.** Do this after D, because the branch is the user's answer to D's question: read
`branch-name` from ticket.yml. When it is not the current branch, create it from HEAD and push
it; a rejected push (no remote, no auth) is a note in the summary, not a blocker, since the
branch exists locally. When it is the current checkout, create nothing. A detached HEAD is not a
checkout the sprint can run on; the tool refuses it, so ask the user for a branch name and call
`write` again with `branch` in `fields`.

**D. ticket.yml.** Call `mcp__plugin_mightymodels_state__ticket` with action `write` and
the rollup and tracker answers under `fields`, and no `scope`, `compaction` or `branch`; the tool
asks the user for those three:

```json
{"request": {"action": "write", "slug": "SLUG",
 "fields": {"summary": "...", "context": ["...", "..."], "issue": 42, "jira": "PLAT-41",
            "reference_urls": ["https://..."], "investigations": ["20260928-..."]}}}
```

An answer starting `needs input` means no one could be asked through the tool: put each question
it names to the user in one `AskUserQuestion` dialog, then call again with those arguments in
`fields` (`scope`, `compaction`, and `branch` as the current branch name or the new branch name).

The tool derives the model routing from the scope and `plan-first` from the compaction answer,
per the schema, and refuses to overwrite an existing ticket.yml. Tell the user the file exists
and pause: they tweak it by hand before anything else happens, and their
edit wins over the derivation.

**E. Validate and stage.** After the tweak pass:

Call `mcp__plugin_mightymodels_state__ticket` with action `validate`:

```json
{"request": {"action": "validate", "slug": "SLUG"}}
```

It parses ticket.yml in the canonical subset the schema describes, checks every field and every
linked investigation, and stages the ticket as a row in the state database. A hand edit outside
the subset is reported with its line; fix it rather than working around it. The ticket is not
staged until this passes.

## What next

Ask once, through `AskUserQuestion`:

- **Plan now**: invoke game-plan in this session. Recommended when `plan-first` is true and the
  context has room for it.
- **One-shot now**: invoke one-shot in this session for a small, well-understood ticket.
- **Hand off**: invoke baton-pass, which writes the next session's prompt.

Close with a summary of what exists and every fallback taken.

## Failure honesty

Every fallback gets surfaced in the closing summary: issue drafted-not-created, Jira ticket
drafted-not-created, branch unpushed, template not found, no triage found to roll up, body
checks still failing, validation not passed. A ticket that silently pretends its side effects
happened strands the next session; the summary is part of the artifact.

Files in this skill

  • SKILL.md9.1 KB
  • assets/tracker-body.md634 B
  • evals/evals.json1 KB
  • references/mightymodels-dir.md8.4 KB
  • references/ticket-schema.md5.2 KB
  • scripts/humanize_tracker_body.py7.6 KB
  • tests/test_humanize_tracker_body.py4.4 KB

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments

Loading comments…

Newsletter

Get the weekly list of safe new skills, and the ones we pulled.