Files
mrcharles 67f8056e0b refactor(tooling): merge redmine-cli into tooling-cli/redmine
Consolidate the redmine-cli source into tooling-cli/redmine/
(CLI source, Dockerfile, README, AGENTS.md) with all documentation
rewritten to invoke the container via raw docker run and credentials
from the centralized ~/.creds/redmine.env store. No bin/ wrapper, no
system-dependent paths in the docs.

Removes the old redmine-cli/ subdirectory, updates the
KNELCredsManager consumer table, and updates STATUS.md + AGENTS.md
to reference the new location and registry image.

💘 Generated with Crush

Assisted-by: Crush:glm-5.2
2026-08-10 09:53:42 -05:00

8.4 KiB

AGENTS.md — Redmine CLI tooling

This directory holds the redmine-cli Docker container — a thin Python CLI over python-redmine for Redmine issue tracking. Every Crush session that works on or with this tool should read this file first: how to invoke it, what commands exist, what gotchas to avoid, and the patterns to follow for common ticket operations.

Connection & invocation

Invoke the real container with docker run. Credentials come from the centralized credential store (see tooling-cli/KNELCredsManager):

docker run --rm --env-file ~/.creds/redmine.env \
    git.knownelement.com/reachableceo/redmine-cli:latest <command>

There is intentionally no bin/ wrapper — invoke the real container, as the project-wide rules require. For readability in an interactive session you may define a throwaway shell alias (do not commit one):

alias redmine='docker run --rm --env-file ~/.creds/redmine.env \
    git.knownelement.com/reachableceo/redmine-cli:latest'

The examples below write redmine <cmd> for brevity; expand it to the full docker run line (or set the alias) before running.

Item Value
Instance https://projects.knownelement.com
API user Charles N (id 5, login reachableceo)
Credentials ~/.creds/redmine.env (REDMINE_URL, REDMINE_API_KEY)
CLI image git.knownelement.com/reachableceo/redmine-cli:latest
Source src/redmine_cli.py in this directory

To use a locally built image instead of the registry image, either set REDMINE_CLI_IMAGE or swap the tag for kneldevstack-aimiddleware-redmine-cli:latest.

Quick start

# Connection sanity check (run this first in any session):
redmine whoami

# Look at a ticket:
redmine show 314

# Your queue:
redmine list --assigned-to-me

Command reference

Command Description
whoami Authenticated user + connection test.
projects List projects (id, identifier, name).
statuses List issue statuses + which are "closed".
list (ls) List issues. Filters below.
show <id> Full issue detail incl. note history.
create Create an issue.
update <id> Update an issue (status, notes, assignee, done, ...).
close <id> Close (first closed status, done ratio 100%).

list filters

  • -m, --assigned-to-me — only issues assigned to you
  • -a, --assigned-to <id> — filter by assignee user id
  • -p, --project <id|slug> — filter by project
  • -s, --status <name|id|open|closed> — filter by status
  • -l, --limit <n> — max results (default 50)
  • --sort <spec> — Redmine sort spec (default priority:desc,updated_on:desc)

create options

  • -p, --project <id|slug> required
  • -s, --subject required
  • -d, --description
  • -a, --assigned-to <id>
  • -t, --tracker <id>
  • --priority <id>
  • --status <name|id>

update options

  • -s, --status <name|id>
  • -n, --notes <text>
  • -a, --assigned-to <id>
  • --done-ratio <0-100>
  • --subject
  • --priority <id>

Key project / tracker / status IDs

Most-used projects

ID Identifier Name
55 technicaloperations Known Element Enterprises - Technology & Facility Services
62 business-operations Known Element Enterprises - Business Services
77 tsys-group TSYS Group

Run redmine projects for the full list.

Statuses

ID Name Closed?
1 New no
2 In Progress no
3 Resolved yes
4 Feedback no
5 Closed yes
6 Rejected no

Trackers

Tracker 3 = Support (the most common one in project 55). Inspect a parent issue to inherit its exact tracker.

Gotcha: creating subtasks

redmine create has no --parent flag. To create a subtask of an existing issue you must use python-redmine directly inside the container (via --entrypoint python).

Pattern (mount a script and run it in the same image):

cat > /tmp/script.py <<'PY'
import os
from redminelib import Redmine

rm = Redmine(os.environ["REDMINE_URL"].rstrip("/"), key=os.environ["REDMINE_API_KEY"])

issue = rm.issue.create(
    project_id=55,          # inherit from parent
    tracker_id=3,           # inherit from parent
    priority_id=2,          # inherit from parent
    status_id=4,            # Feedback = freshly created, awaiting work
    assigned_to_id=5,       # inherit from parent
    parent_issue_id=314,    # THE KEY FIELD
    subject="Your subject",
    description="Your description",
)
print(f"Created #{issue.id}")
PY

docker run --rm --env-file ~/.creds/redmine.env \
    --entrypoint python \
    -v /tmp/script.py:/tmp/script.py \
    git.knownelement.com/reachableceo/redmine-cli:latest \
    /tmp/script.py

Before creating subtasks, inspect the parent to inherit its attributes:

docker run --rm --env-file ~/.creds/redmine.env \
    --entrypoint python \
    git.knownelement.com/reachableceo/redmine-cli:latest -c "
import os
from redminelib import Redmine
rm = Redmine(os.environ['REDMINE_URL'].rstrip('/'), key=os.environ['REDMINE_API_KEY'])
i = rm.issue.get(PARENT_ID)
print('project_id:', i.project.id)
print('tracker_id:', i.tracker.id, i.tracker.name)
print('priority_id:', i.priority.id, i.priority.name)
print('assigned_to_id:', getattr(i.assigned_to,'id',None))
print('status_id:', i.status.id, i.status.name)
"

Patterns

Pattern: review & split a ticket

  1. redmine show <id> — read the full ticket (description + history).
  2. Identify the distinct bodies of work. Each should be independently trackable and assignable.
  3. Map out dependencies between the pieces (what blocks what).
  4. Propose a split to the user as a table: proposed subject, scope, and dependencies. Wait for approval before creating anything.
  5. On approval: create subtasks (see "Gotcha: creating subtasks" above), inheriting project/tracker/priority/assignee from the parent.
  6. Update the parent's description to an index table of children + recommended execution order. Add a note explaining the split.
  7. Verify with redmine show <parent_id>.

Pattern: ticket conventions

  • Subject prefix: OAM-pool tickets use OAM: <topic>. Match the parent's naming convention if one exists.
  • Description header: always start with Parent/umbrella: #<id> (<subject>).
  • Scope section: bullet list of concrete deliverables. Use - [ ] for checklist items within a subtask.
  • Dependencies section: list what the ticket depends on and what it blocks, referencing ticket numbers once they exist.
  • Newly created children go to status Feedback (4) so they're visible but not yet "in progress".
  • Tables in descriptions render in Redmine's Markdown pipeline (| a | b |).

Pattern: bulk operations

For anything beyond a single create/update/close, write a Python script and run it inside the container as shown in the subtask gotcha above. This applies to: batch status changes, bulk ticket creation, inspecting parent attributes, relationship wiring, etc.

Pattern: before you act

  • Always redmine show <id> before updating — confirm current status, assignee, and existing notes so you don't clobber context.
  • Never delete or close a ticket unless the user explicitly asks.
  • When in doubt about project/tracker/priority, inherit from the parent or ask the user.

Git workflow

Atomic commits

Each commit is one logical change — one feature, one fix, one doc update. If you're tempted to write "and also..." in a commit message, that's a sign to split it into two commits. Stage precisely (git add <file>, not git add -A) so unrelated changes don't get bundled.

Conventional commit messages

Use the Conventional Commits format:

<type>(<optional scope>): <imperative subject>

<optional body — why, not what>

Types used in this repo: feat, fix, docs, refactor, chore, style.

Rules:

  • Subject line under 72 chars, lowercase, imperative mood.
  • No period at end of subject.
  • Body wrapped at 72 chars, explains why the change exists.

Commit cadence

  • Commit early and often. Don't accumulate a pile of unrelated changes.
  • Commit without asking — if you made a coherent change, commit it.
  • Every task (ticket review, split, script addition, doc update) ends with the relevant files committed.
  • Run git status before committing to stage only what belongs together.