Install
$ agentstack add skill-eugenelim-agent-ready-repo-flow-metrics ✓ scanned · ✓ verified — works with Claude Code, Cursor, and more.
Security review
✓ PassedNo issues found. Passed automated security review. · v0.1.0 How review works →
- ✓ Prompt-injection patterns
- ✓ Secret / credential exfiltration
- ✓ Dangerous shell & filesystem operations
- ✓ Untrusted network calls
- ✓ Known-malicious package signatures
What it can access
- ✓ Network access No
- ✓ Filesystem access No
- ✓ Shell / process execution No
- ● Environment & secrets Used
- ✓ Dynamic code execution No
From automated source analysis of v0.1.0. “Used” means the capability is present in the source — more access means more to trust, not that it’s unsafe.
About
Skill: flow-metrics
This skill is the one place to compute Flow Framework / DORA-style metrics over a Jira scope. It composes two upstream skills and emits a canonical JSON / CSV / JSONL block; it does not invent new tracker verbs or replicate them inline.
jiraskill (sibling in this pack) — every Jira read:check,
whoami, get-issue, search, get-project, plus a tightly- allowlisted set of raw GET paths for the custom-field catalog, project-status enumeration, and per-issue changelog pagination.
jira-alignskill (sibling in this pack) — used only for
--program-id / --portfolio-id scope, and only for the four team / program / portfolio enumeration paths. Time-in-state numbers always come from Jira's changelog.
The pipeline (config validation, scope JQL, changelog walk, per-issue derivation, aggregation, cohort split, per-team rollup, notes, meta, output rendering, caching) lives in scripts/flow_metrics/. This SKILL.md tells the agent how to invoke the CLI for common flows; for design details, read the inline module docstrings.
Cross-skill invocation — name, not path
This skill names sibling skills (jira, jira-align) by their name: field, never by path. Install locations vary by IDE and scope, and skills can be renamed at install time. The agent's harness resolves the name to whatever location the user picked. If you find yourself writing a hardcoded skill path, stop — look up the skill by name instead.
Install guidance for the named dependencies lives in manifest.json under deps.skills — that's a where to get them hint, not a runtime path.
Prerequisites
Before computing metrics, confirm:
- The
jiraskill is installed and authenticated. Invoke it:
jira: check. Exit 0 → proceed. Exit 2 → tell the user to run credential-setup skill themselves; do not attempt to read ~/.agentbundle/credentials.env from this skill.
- For program / portfolio scope, the
jira-alignskill is installed
and authenticated. If --program-id or --portfolio-id is in play and jira-align: check fails, exit 3 and surface upstream stderr verbatim.
- The Jira
team_field.idyou've configured (default
customfield_10001 in the shipped state config) exists in this instance's field catalog. If it doesn't, the skill exits 2 at startup naming the missing field.
Invocation
The skill ships one CLI. Two equivalent forms (both call the same flow_metrics.main):
# Installed package — exposes a `flow-metrics` shim on PATH:
flow-metrics --project PROJ
# Or any environment where the package is on PYTHONPATH:
python -m flow_metrics --project PROJ
The spec's examples use the bare flow-metrics form. From a working copy of this pack, add the package to PYTHONPATH first:
export PYTHONPATH="$(pwd)/scripts:$PYTHONPATH"
python -m flow_metrics --help
Every example below uses the bare form; substitute python -m flow_metrics if you're invoking from a clone.
CLI flags
The full flag surface:
--project KEY— Jira project key. Mutually exclusive with
--program-id / --portfolio-id.
--team NAME— Optional sub-scope within a project. Resolution
rule depends on team_field.kind (single_value or array). Only valid with --project.
--program-id ID— Jira Align program ID. Triggers a Jira Align
join for team mapping.
--portfolio-id ID— Jira Align portfolio ID. Triggers a rollup
across constituent programs / teams.
--from ISO,--to ISO— Window bounds,YYYY-MM-DD. Both
inclusive of the named day. Default: --to = today (UTC), --from = today − 90 days.
--jql ""— Extra JQL ANDed into the scope query. Always
wrapped as () AND () — your expression is parenthesised verbatim.
--align-filter ""— Extra OData ANDed into Jira Align
queries with the same parenthesisation rule.
--cohort-jql ""— Issues matching this JQL are marked
cohort: true in the output. Aggregate mode emits a cohort_breakdown block; per-issue mode tags each row.
--metrics LIST— Comma list. Default: all ten. Names:
cycle_time, lead_time, throughput, wip, flow_load, rework_rate, flow_time, flow_efficiency, flow_distribution, defect_ratio. Unrequested metrics are omitted from aggregates (not emitted as null); meta.metrics_requested records the resolved list.
--state-config FILE— JSON file mapping raw statuses to
canonical states. Defaults to the shipped references/states.default.json.
--issuetype-config FILE— JSON file mapping issuetypes to Flow
Distribution buckets. Defaults to references/issuetypes.default.json.
--team-field-override ID— Overrideteam_field.idfrom the
state config for this run.
--align-join-field NAME— Override the Jira ↔ Jira Align join
field. Defaults to the align_join_field entry in the state config; if neither is set and Jira Align scope is requested, exit 2.
--align-teams-path PATH— Override the Jira Align endpoint
used to enumerate teams in a program. Must match one of the four allowlisted jira-align raw GET patterns.
--include-subtasks— Include subtasks in throughput, cycle
time, lead time, flow efficiency, rework rate. Default: false. Flow Distribution is always insensitive to this flag.
--format json|csv— Output format. Default:json.--output FILE— Write to file instead of stdout. Required for
--per-issue. Path is rejected if it lands under a system root.
--per-issue— Emit one JSONL row per issue with all derived
fields, instead of aggregates. Requires --output.
--no-cache— Bypass the on-disk cache at
.context/flow-metrics/cache/.jsonl.
--verbose— Debug logging (state-transition walks, cache hits,
upstream skill invocations).
--yes— Overwrite--output FILEwithout prompting.
Exactly one of --project, --program-id, --portfolio-id must be provided. --team is only valid with --project.
Common flows
Each example is a literal command line the agent can run.
Project-scope, default 90-day window
flow-metrics --project PROJ
JSON to stdout. The shipped default state config maps the common Jira workflow ("To Do" / "In Progress" / "Done" / "Won't Do") out of the box.
Project-scope with a specific window and JQL filter
flow-metrics \
--project PROJ \
--from 2026-02-01 --to 2026-04-30 \
--jql 'labels = ai-assisted AND component = checkout'
Jira Align program scope (joins via Jira Align)
flow-metrics \
--program-id 42 \
--align-join-field "Program ID" \
--from 2026-02-01 --to 2026-04-30
--align-join-field is required for Align scope unless the state config provides it.
Cohort split (A/B comparison)
flow-metrics \
--project PROJ \
--cohort-jql 'labels = ai-assisted' \
--format json
Output gains a cohort_breakdown block with cohort and control sides. Cohort-jql matching zero issues produces an empty cohort with throughput: 0 and null percentiles — exit 0.
Filter to a subset of metrics
flow-metrics \
--project PROJ \
--metrics throughput,cycle_time,defect_ratio
Only the requested metrics appear in aggregates. meta.metrics_requested records the resolved list. flow_distribution and defect_ratio are separate keys — requesting one does not auto-include the other.
Bypass the on-disk cache
flow-metrics --project PROJ --no-cache
Use when the underlying Jira data has changed and you suspect cache staleness. Cache lives at .context/flow-metrics/cache/.jsonl.
Per-issue dump (downstream consumer input)
flow-metrics \
--project PROJ \
--per-issue \
--output .context/flow-metrics/per-issue.jsonl
JSONL on disk, one row per in-scope issue. Downstream consumers (notably ai-adoption-report) MUST filter on delivered_in_window: true before computing delivery-based metrics.
Don't
- Don't bypass the upstream-skill allowlist. This skill invokes
only the allowlisted verbs and raw GET paths. Any other invocation is a regression. If a verb is missing, extend the jira or jira-align skill — don't shim around it here.
- Don't read
credentials.envfrom this skill. Credentials live
in the jira / jira-align skills and are isolated from this one. Authentication failures surface as upstream exit 3; the fix is to run the upstream skill's setup_credentials.sh, not to read its config file from here.
- Don't issue write verbs. This skill is read-only. No
create-issue, update-issue, delete-issue, transition, comment, attach — and no raw POST / PUT / PATCH / DELETE to any upstream skill. A contract test wraps the upstream skills and fails on any out-of-allowlist call.
- Don't add
numpyor any other pip dependency. v1 is stdlib
only — percentiles use statistics.quantiles(..., method="exclusive") at indices 49 / 74 / 89 for p50 / p75 / p90. The schema validator used by the contract test is the same stdlib-only posture; do not add jsonschema to satisfy it.
- Don't infer the
align_join_field. Instances vary; silently
picking customfield_10001 is a wrong-answer risk. If neither --align-join-field nor the state config sets it and Align scope is requested, exit 2 with a clear message.
- Don't normalise JQL semantically in v1.
normalize_jqlonly
collapses whitespace; two semantically equivalent JQL expressions with different clause order produce different cache files. That's the documented v1 trade.
- Don't paraphrase the metric definitions. They are pinned
and tested. If a metric "feels wrong", read the module docstrings before changing anything.
Security rules
This skill operates under a read-only contract with credential isolation:
- Read-only contract: the upstream-skill allowlist names every
verb and raw GET path this skill is permitted to invoke. Any other upstream invocation, including the raw POST / PUT / PATCH / DELETE escape hatches, is forbidden and enforced by a contract test that wraps the upstream skills.
- Credential isolation: this skill **never reads
credentials.env** or any other secret file directly. Credentials belong to the jira / jira-align skills; this skill invokes them by name and lets them load their own credentials. If jira: check fails, surface the error and tell the user to run the upstream skill's setup — do not attempt to authenticate on its behalf.
- No write verbs: this skill emits no
POST/PUT/PATCH/
DELETE HTTP requests, and invokes no write-class verbs (transition, comment, create, update, delete, attach) on any upstream skill. The output is metrics; it never mutates Jira state.
- Path safety:
--output,--state-config,--issuetype-config
are rejected if they resolve under a privileged system root (POSIX: /etc, /sys, /proc, /dev, /boot; Windows: the system drive's Windows, Program Files, and Program Files (x86) directories), or if they contain a null byte. Exit 2.
Edge cases
The key edge cases to know about:
- Cancelled issues. An issue transitioning into a
terminal_non_delivery_states canonical state (default: cancelled) in-window with no first-ever delivery in-window is cancelled-in-window. Excluded from throughput, cycle time, lead time, flow efficiency, and Flow Distribution; counted in notes. A cancel-then-reopen-still-active-at---to issue is also in WIP — both signals are reported simultaneously.
- Empty cohort.
--cohort-jqlmatching zero issues produces an
empty cohort sub-object with throughput: 0 and percentile fields null. The skill exits 0.
- Permission undercounting. Jira silently omits issues the caller
lacks browse permission on. For project scope, the skill compares the JQL count against jira: get-project and emits a notes entry recording the delta. Field-level permission undercount on the team_field is also detected and reported as a synthetic (no team) row in per_team. The skill does not retry as a different user or escalate. meta.caller records the calling account so downstream consumers can spot cross-account discrepancies.
- Changelog pagination (Cloud regression). Cloud Jira's
/search/jql endpoint returns at most ~100 inline changelog entries per issue. The skill detects "more pages exist" via isLast, nextPageToken, or histories.length /changelog. Long-lived issues silently lose cycle-time math without this, so the pagination contract is required, not optional.
- Unmapped raw status. Any raw status not listed under any
canonical_states entry causes exit 2 at startup with the offending name. The shipped default config maps "Won't Do" / "Cancelled" / "Duplicate" to cancelled deliberately so first-run users on a normal Jira workflow get accurate throughput out of the box.
- Issue with no commitment_state transition (closed directly from
backlog). Delivered-in-window = true; cycle-eligible = false. Contributes to throughput and lead time. Excluded from cycle time.
--per-issuewithout--output. Exit 2 — JSONL must go to a
file.
Output contract
The canonical wire format is pinned by references/output.schema.json (JSON Schema draft 2020-12). The shape:
meta— caller, scope, window, sources, metrics_requested,
schemaversion, generatedat, stateconfigsha, issuetypeconfigsha, perteamdouble_counted, and optionally cohort_jql (omitted when --cohort-jql was not provided).
aggregates— one key per requested metric. Unrequested metrics
are absent, not null. additionalProperties: false in the schema pins this.
cohort_breakdown— optional. Emitted only when--cohort-jqlis
set AND --per-issue is not set. Carries cohort and control sub-objects with the same metric shape as aggregates.
per_team— optional array of per-team rows. Emitted when scope is
--program-id / --portfolio-id, or when scope is --project and the resolved issue set spans more than one distinct team value.
notes— array of descriptive strings, lex-sorted.
Output is canonicalised at serialisation: codepoint-sorted object keys (except flow_distribution which uses a fixed bucket order), floats rounded to 4 decimal places, per_team sorted by team name codepoint. The schema does not re-validate canonicalisation rules — those are enforced by the renderer's contract tests.
Further reading
The module docstrings in scripts/flow_metrics/ cover:
- metric definitions and core population predicates (
predicates.py,aggregate.py), - the upstream-skill allowlist and verbs (
upstream.py), - state-config and issuetype-config schemas (
config.py), - canonicalisation rules and output rendering (
output.py), - cache-key derivation (
cache.py), - edge-case handling (
per_issue.py,notes.py).
Source & license
This open-source skill is cataloged on AgentStack and links to its original source — we do not rehost the code.
- Author: eugenelim
- Source: eugenelim/agent-ready-repo
- License: Apache-2.0
Install and usage instructions live in the source repository linked above.
Reviews
No reviews yet — be the first.
Write a review
Versions
- v0.1.0 Imported from the upstream source.