Skip to content

Getting Started

m4bwav edited this page Oct 26, 2026 · 3 revisions

What runs where

askwright is one folder, skills/askwright: the skill (SKILL.md and two references), scripts/ask.py, and the page (scripts/page/index.html, app.js, app.css). ask.py uses the Python standard library only. CI runs its tests on Windows, macOS and Linux with Python 3.9 and 3.14; the examples on this wiki were run on Linux and Windows (see Home). macOS was not run for the wiki, only in CI. Use python on Windows and python3 on macOS and Linux.

The repository's page tests run the page in an installed Chrome or Edge (CI uses Chrome on Ubuntu); other browsers were not tested. The served page loads nothing from the network, and video should be H.264 with AAC sound so every browser plays it (lint warns otherwise when ffprobe is installed).

Installing

Route Command Run for this wiki
Claude Code plugin /plugin marketplace add m4bwav/askwright, then /plugin install askwright@askwright not tested
Release zip download askwright-0.2.0.zip from the releases and unzip it yes: the zip holds skills/askwright, README.md, LICENSE and SECURITY.md (61,076 bytes)
Clone and link git clone https://github.com/m4bwav/askwright, then link skills/askwright into the agent's skills folder not tested

The link for the last route, on Windows (a junction needs no admin rights) and on macOS or Linux:

New-Item -ItemType Junction -Path "$HOME\.claude\skills\askwright" -Target "$PWD\askwright\skills\askwright"
ln -s "$PWD/askwright/skills/askwright" ~/.claude/skills/askwright

Agents that read Agent Skills from other folders (~/.agents/skills, ~/.copilot/skills, .cursor/skills) take the same link there. Check the install with:

$ python ask.py --version
0.2.0
$ echo $?
0

The first set

The transcripts on this wiki run ask.py as python ask.py; give its path instead (python skills/askwright/scripts/ask.py) when you run it from elsewhere. The working folder holds the sets, here ask/first.

Start with an empty set:

python ask.py new ask/first --title "Try askwright"

ask/first/questions.json then holds the frame to fill in:

{
  "askwright": 1,
  "id": "first",
  "title": "Try askwright",
  "context": "",
  "asked_by": "",
  "media_roots": [],
  "questions": []
}

Linting it now fails, because a set needs at least one open question:

$ python ask.py lint ask/first
{
  "ok": false,
  "set": "first",
  "errors": [
    {
      "rule": "no-questions",
      "q": null,
      "msg": "the set has no open questions"
    }
  ],
  "warnings": []
}
$ echo $?
1

Put two questions in, a confirm and a choice. Every question says why it matters and carries the agent's guess with a confidence: high is shown under the options, low waits behind "Show my guess".

{
  "askwright": 1,
  "id": "first",
  "title": "Try askwright",
  "questions": [
    {
      "id": "render",
      "kind": "confirm",
      "title": "Tonight's render",
      "question": "When should the final render run?",
      "why": "It holds the GPU for six hours, so nothing else renders meanwhile.",
      "options": [
        {"id": "tonight", "label": "Render tonight"},
        {"id": "saturday", "label": "Wait until Saturday", "consequence": "The cut slips two days."}
      ],
      "guess": {"option": "tonight", "why": "Nothing else is queued tonight.", "confidence": "high"}
    },
    {
      "id": "music",
      "kind": "choice",
      "title": "Credits music",
      "question": "Which track should play over the credits?",
      "why": "The credits run 40 seconds and the track sets the last mood.",
      "options": [
        {"id": "piano", "label": "The piano theme"},
        {"id": "drums", "label": "The battle drums"},
        {"id": "silence", "label": "No music, just the wind"}
      ],
      "guess": {"option": "drums", "why": "The film ends on the charge.", "confidence": "low"}
    }
  ]
}

python ask.py lint ask/first now prints {"ok": true, "set": "first", "errors": [], "warnings": []}. Serve it in the background:

$ python ask.py serve ask/first --detach
{
  "url": "http://127.0.0.1:<port>/",
  "pid": <pid>,
  "port": <port>,
  "set_dir": "/work/proj/ask/first",
  "started": "<time>",
  "ok": true,
  "detached": true
}
$ echo $?
0

Open the url (or add --open). The run behind this page sent the server the two answers the page would send for a person who picked "Render tonight" and left only a note on the music question, "Ask the composer first". status then reports:

$ python ask.py status ask/first
{
  "ok": true,
  "set": "first",
  "title": "Try askwright",
  "open": 2,
  "rev": 2,
  "done": false,
  "paused": false,
  "last_mark": null,
  "server": {
    "url": "http://127.0.0.1:<port>/",
    "pid": <pid>,
    "port": <port>,
    "set_dir": "/work/proj/ask/first",
    "started": "<time>",
    "alive": true
  },
  "answered": [
    "render"
  ],
  "unsure": [],
  "note_only": [
    "music"
  ],
  "unanswered": [],
  "waiting": [],
  "not_applicable": [],
  "stale": []
}
$ echo $?
0

The note without a pick is note_only, never a choice. read gives every answer with its label, the guess and whether they matched; Commands shows its output. When you are done, stop the server:

$ python ask.py stop ask/first
{
  "ok": true,
  "stopped": true,
  "pid": <pid>
}
$ echo $?
0

What the set folder holds afterwards

Beside questions.json the server writes answers.json (every answer, with a revision number), events.jsonl (visits, answers, "done" and "pause" marks, rounds added), attachments/ (pasted or dropped images), server.json (url, pid, port, folder, start time and the page token) and server.log. stop removes server.json; the rest stays. Do not edit these files by hand.

Removing it

For the plugin, /plugin uninstall askwright@askwright (not tested). For a linked or unzipped copy, delete the link or the folder. askwright writes nothing outside the set folders it is given, so there is nothing else to remove.

Clone this wiki locally