Usage#
Day-to-day workflow for the shared snell- corpus: scaffold and
edit responses, quality-gate in CI, browse with the TUI, convert with
pandoc, and use free-tier Jira REST only for explicit probe / import /
one-shot comment — never unattended bulk sync into Jira.
Quick start#
cargo install --git https://github.com/HaoZeke/canonic --locked
canonic doctor
canonic list
canonic tui # interactive browser
canonic check && canonic lint --engine harper
From a checkout of this repo (corpus sample included):
cargo build --release
./target/release/canonic list
./target/release/canonic tui
Operational loop#
-
1
Scaffold or import
newfor a template, orimport-jiraintocorpus/imports/. -
2
Edit & gate
check+ Harper lint; promote only when clean. - 3 Browse & search TUI or CLI list/search/dedupe before publishing.
-
4
Render / post
convertfor wiki paste, or explicitjira-comment(one file → one issue).
Command reference#
Command |
Purpose |
Notes |
|---|---|---|
|
Probe pandoc, Vale, Harper, optional Jira env |
Exit |
|
Interactive corpus browser |
See Interactive TUI |
|
List published responses |
|
|
Scaffold check-clean |
|
|
Copy import draft → |
Runs quality check first; refuses dirty drafts |
|
Quality gate (prefix, sop, team sign-off) |
Exit |
|
Vale and/or Harper |
|
|
Markdown → Jira wiki via pandoc |
Whole corpus if PATH omitted; |
|
Rebuild Tantivy index |
Default |
|
BM25 full-text search |
Requires prior |
|
Near-duplicate pairs |
|
|
Free REST identity ( |
Env auth; no Marketplace apps |
|
Pull comments as review drafts |
Writes |
|
Post one pandoc-jira comment |
Explicit, not bulk; |
Command map (cards)#
- canonic doctorpandoc / tooling status
- canonic tuiinteractive browser
- canonic listlist response files
- canonic checkquality gate · exit 1 on findings
- canonic lint --engine harper
- canonic new "Title"scaffold snell- template
- canonic promote PATH.mdimport → responses after check
- canonic reindex
- canonic search "project space backup"
- canonic dedupe --reindex --threshold 1.0
- canonic dedupe --threshold 0.5 --json
- canonic convert PATH.mdpandoc jira writer
- canonic jira-probemyself · free platform only
- canonic import-jira "JQL"drafts under corpus/imports/
- canonic jira-comment --issue KEY PATH.mdexplicit POST comment
Interactive TUI#
canonic tui opens a ratatui corpus browser over corpus/responses/
(override with --corpus).
Key |
Action |
|---|---|
|
Next response |
|
Previous response |
|
Filter by id, title, tags, or body |
|
Run quality check on the whole corpus |
|
Convert selection → jira wiki (preview only) |
|
Lint selection with in-process Harper |
|
Rebuild Tantivy index |
|
Search index (filter text or selected title) |
|
Reload markdown from disk |
|
Doctor / tooling snapshot in preview |
|
Help overlay |
|
Quit |
Important
The TUI never POSTs to Jira. Convert preview stays local. Publishing is
always an explicit canonic jira-comment (or human paste of convert
output).
Recipes#
New response from scratch
The filename is snell- plus a slug of the title (override with --id).
canonic new "Project space is not a backup" --tags storage,project-space
# → corpus/responses/snell-project-space-is-not-a-backup.md
$EDITOR corpus/responses/snell-project-space-is-not-a-backup.md
canonic check
canonic lint --engine harper
canonic tui
Import → edit → promote
export JIRA_BASE_URL=https://your-instance.atlassian.net
export JIRA_EMAIL=you@example.org JIRA_API_TOKEN=...
canonic jira-probe
canonic import-jira "project = HSP AND labels = canned-response" --dry-run
canonic import-jira "project = HSP AND labels = canned-response"
$EDITOR corpus/imports/snell-….md # team sign-off, shared voice
canonic promote corpus/imports/snell-….md
canonic check
Search before answering a ticket
canonic reindex
canonic search "project space backup"
canonic dedupe --reindex --threshold 1.0
canonic tui # / to filter, c to preview jira markup
Publish one comment (human-gated)
canonic convert corpus/responses/snell-demo-shared-quota.md
canonic jira-comment --issue HSP-101 \
corpus/responses/snell-demo-shared-quota.md --dry-run
canonic jira-comment --issue HSP-101 \
corpus/responses/snell-demo-shared-quota.md
Full paste-ready session#
canonic doctor
canonic list
# shipped demo (no scaffold required):
canonic convert corpus/responses/snell-demo-shared-quota.md
canonic check
canonic lint --engine harper
canonic tui
# scaffold a new response (slug from title):
canonic new "Example topic" --tags example
# → corpus/responses/snell-example-topic.md
$EDITOR corpus/responses/snell-example-topic.md
canonic check
canonic convert corpus/responses/snell-example-topic.md
canonic reindex
canonic search "shared quota"
canonic dedupe --reindex --threshold 1.0
JIRA_BASE_URL=https://your-instance.atlassian.net \
JIRA_EMAIL=you@example.org JIRA_API_TOKEN=... \
canonic jira-probe
canonic import-jira "project = HSP AND labels = canned-response" --dry-run
canonic promote corpus/imports/snell-example-hsp-101.md
canonic jira-comment --issue HSP-101 \
corpus/responses/snell-demo-shared-quota.md --dry-run
Corpus layout#
Responses live under corpus/responses/ as snell-<topic-slug>.md.
Import drafts land under corpus/imports/ (gitignored) until promote.
Front matter is enforced by canonic check:
---
id: snell-<topic-slug>
title: Human-readable title
prefix: snell
tags: [tag-one, tag-two]
sop: none
---
Important
idand filename stem must match and start withsnell-prefix: snellrequired (shared library convention; no personal prefixes)sop:required — Confluence / service-desk wiki URL, or the literalnonewhen no SOP page exists yetClosings must be team-generic (e.g.
Support Team), not personal names
.gitignore excludes the Tantivy index under .canonic-index/ and
review drafts under corpus/imports/ (never commit un-promoted imports).
Team review via GitLab mirror#
For team merge-request review on a GitLab remote while the primary clone is elsewhere, mirror a branch:
export CANONIC_GITLAB_REMOTE=git@gitlab.example.com:your-group/canonic.git
scripts/mirror-to-gitlab.sh
Open the merge request on that GitLab. Do not bulk-push the library into
Jira; only convert paste or explicit jira-comment publish one answer.
CI quality gate#
GitHub Actions runs cargo test --locked --all-targets, then on the release
binary:
canonic list/canonic checkoncorpus/responses/canonic lint --engine harper(in-process; domain vocab for tooling jargon)canonic convertsmoke on the seeded sample (pandoc installed in CI)
Keep published responses check-clean so the gate stays green.
Dedupe#
dedupe rebuilds or reuses the Tantivy index, then for each response runs a
self-query (title + content terms) and reports other documents that rank above
--threshold. Pair reasons include the Tantivy score and a content Jaccard
similarity for a second opinion.
Tip
Use a high threshold when you only want strong near-copies (curation
before a Jira migration). Drop the threshold and add --json when you
want a wider review list.
Free Jira REST (no paid Marketplace apps)#
canonic uses only native platform REST (Cloud Free API tokens or Server/DC PAT). No Marketplace extensions, ScriptRunner, or paid service-desk canned-response admin APIs.
Probe
canonic jira-probe calls GET /rest/api/2/myself (and serverInfo when
available). Exit non-zero on auth or reachability failure.
Import (read path)
import-jira <jql> searches free search paths (api/2 then api/3 variants),
fetches comments, converts wiki/ADF → markdown, and writes one draft per
issue under corpus/imports/ — never into corpus/responses/.
--dry-run lists targets without fetching comments.
Comment write (explicit)
jira-comment --issue KEY PATH.md converts markdown with pandoc’s free
jira writer, then posts via platform REST:
Server/DC:
POST /rest/api/2/issue/{key}/commentwith wiki string bodyCloud Free (
*.atlassian.net):POST /rest/api/3/issue/{key}/commentwith minimal ADF — required by Cloud v3, no paid apps
--body-format auto|wiki|adf overrides host detection. --dry-run prints the
converted wiki without POSTing. One file, one issue, human-gated — not bulk sync.
Official free map (platform only)
Command |
Endpoint |
Body |
|---|---|---|
|
|
— |
|
|
wiki or ADF read |
|
|
pandoc jira text |
Authentication (environment):
Variable |
Role |
|---|---|
|
Required, e.g. Cloud Free instance URL |
|
Basic auth (Jira Cloud Free API token) |
|
Raw |
Agent skill#
Day-to-day agent instructions ship at
.agents/skills/canonic-canned-loop/SKILL.md (import → scaffold/promote →
check/lint → TUI → convert / jira-comment). Install or trust that path in
your agent skill loader.
Exit codes#
Command |
Non-zero meaning |
|---|---|
|
|
|
|
|
|
|
check failed or destination exists without force |
GitLab mirror#
scripts/mirror-to-gitlab.sh pushes the current branch to a second remote for
team merge-request review on self-hosted GitLab:
CANONIC_GITLAB_REMOTE=git@gitlab.example:group/canonic.git scripts/mirror-to-gitlab.sh
Pass a branch name as the first argument to override the current branch.
Jira smoke (Docker / Nix)#
CI and local free-tier smoke (fixture container, no Marketplace apps):
cargo build --release
./scripts/ci/jira-docker-smoke.sh
Nix dockerTools image:
nix build .#jira-fixture-image
docker load < result
./scripts/ci/jira-docker-smoke.sh
Heavy official Atlassian Jira Software (developer timebomb; multi-GB RAM):
./scripts/jira-real/run-import-smoke.sh