# imdone-cli

Turn Jira or GitHub issues into a local Markdown workspace for AI and humans, then sync updates back to your provider.

`imdone-cli` pulls issue content and attachments into local Markdown and files, then syncs your updates back to Jira or GitHub so developers and AI agents can work locally in the editor while product, design, and stakeholders stay in Jira or GitHub.

Many teams keep their stories and requirements in Jira or GitHub, but let the AI execution context drift into the working branch or into a branch independent of the work. That leads to broken handoffs, rework, and missing context. imdone keeps the working context with the issue, where the work already lives, and turns it into durable, reviewable local files.

`imdone pull` and `imdone push` keep that context in sync. Bundled skills help teams turn raw tickets into buildable work, create and repair issue structure, reduce handoff risk, and inspect delivery flow from local issue history.

**What you get:**

- Keep AI and human working context in Jira or GitHub issues instead of hiding it in a branch independent of the work.
- Work from local Markdown in your editor without giving up provider-native collaboration.
- Track feature work and feedback loops visually on the [imdone kanban board](https://imdone.io/markdown-kanban-board).
- See issue lifecycle history locally in `changelog.yml`, so cycle-time inputs stay visible in the issue folder.
- Use bundled skills to create and structure issues, refine stories, define success metrics, tighten plans, assess handoff quality, render PDFs, and generate archived cycle-time reports.
- Reduce handoff risk by keeping decisions, evidence, and delivery notes tied to the issue.

[![npm version](https://img.shields.io/npm/v/imdone-cli.svg)](https://www.npmjs.com/package/imdone-cli)
[![npm downloads](https://img.shields.io/npm/dm/imdone-cli.svg)](https://www.npmjs.com/package/imdone-cli)
![imdone-cli demo](https://imdone.io/video/Imdone-Add-Demo-720p-15fps.gif)

<!-- toc:start -->
## Table of Contents

- [Requirements](#requirements)
- [Get Started](#get-started)
- [1Password-Managed Credentials](#1password-managed-credentials)
- [Core Commands](#core-commands)
- [Bundled AI Skills](#bundled-ai-skills)
- [Support & Feedback](#support-feedback)
- [Commands](#commands)
- [Status Mapping](#status-mapping)
- [GitHub Integration](#github-integration)
- [Markdown Formatting Guide](#markdown-formatting-guide)
- [Detailed Documentation](#detailed-documentation)
- [imdone-cli and Git](#imdone-cli-and-git)
- [Attachment Versioning](#attachment-versioning)
- [Troubleshooting](#troubleshooting)

<!-- toc:end -->

## Requirements

- Node.js v22 or higher installed
- git installed
- **For Jira:**
  - Jira account with API access
  - A Jira API token with read and write permissions for the project
- **For GitHub:**
  - GitHub account with repository access
  - A GitHub Personal Access Token: classic tokens need `repo`; fine-grained tokens need repository `Contents: Read and write`, `Issues: Read and write`, and `Pull requests: Read and write`
- A git repository used for your software development (optional — `imdone init` works in any directory)

## Get Started

```bash
# 1) Install
npm i -g imdone-cli

# 2) Initialize and pull issues
imdone init

# 3) Open stories in your editor (Markdown next to your code)
code . # nvim .
```

**What you'll see:** A `backlog/current-sprint/` directory with one folder per issue. Each issue folder contains the main issue content, comments, lifecycle history in `changelog.yml`, and an `attachments/` folder. Edit Markdown locally; `imdone push` syncs changes back to Jira or GitHub.

The same synced issues can also be monitored visually on the [imdone kanban board](https://imdone.io/markdown-kanban-board).

You can try `imdone-cli` without creating an account. Anonymous CLI users get 50 provider syncs on their device, then 10 provider syncs per month forever on that same device. A provider sync is a command that writes changes back to Jira or GitHub, such as `imdone push`, `imdone add`, or `imdone move`; reading and local discovery commands such as `imdone pull`, `imdone ls`, and `imdone show` do not use that allowance.

```
backlog/
├── .imdone/
│   ├── config.yml
│   └── templates/
│       └── story.md
├── current-sprint/
│   ├── PROJ-123-Fix_login_bug/
│   │   ├── attachments/
│   │   │   └── error-screenshot.png
│   │   ├── changelog.yml
│   │   ├── comments-PROJ-123.md
│   │   └── issue-PROJ-123.md
│   └── PROJ-124-Add_user_dashboard/
│       ├── attachments/
│       ├── changelog.yml
│       ├── comments-PROJ-124.md
│       └── issue-PROJ-124.md
```

## 1Password-Managed Credentials

`imdone` now supports direct 1Password-backed credentials without a wrapper script.

Recommended flow from your software project root:

```bash
imdone init --1password
imdone ls
imdone push
```

Requirements:

- 1Password CLI: `brew install 1password-cli`
- A signed-in 1Password account: `op signin`

What the direct integration does:

- Stores Jira and GitHub credentials in 1Password and replaces plain backlog `.env` secrets with `op://...` references.
- Resolves those `op://...` references automatically when you run `imdone` directly.
- Prompts you to migrate when `op` is available but the repo is still using plain provider secrets in `.env`.

By default, migration writes items to the `Employee` vault. Set `IMDONE_1PASSWORD_VAULT` to target a different vault before running setup:

```bash
IMDONE_1PASSWORD_VAULT=Private imdone init --1password
```

## Core Commands

```bash
imdone pull     # Bring issues/comments/attachments into Markdown
imdone status   # See what's changed locally (alias: st)
imdone push     # Push your Markdown edits back to your provider
imdone hdd      # Launch Codex or Claude with HDD story context
```

<small>Uninstall anytime: `imdone destroy && npm uninstall -g imdone-cli` (your code is untouched; `backlog/` is git-ignored).</small>

---

## Bundled AI Skills

`imdone-cli` ships with backlog-local skills for Claude Code and Codex. They help teams turn issue context into execution-ready work without inventing a separate planning system or burying delivery context in side docs.

| Skill | Problem it solves |
| --- | --- |
| `imdone-ls` | You need to find the right local Jira or GitHub issues quickly without jumping back to the provider UI or hand-scanning the backlog. |
| `imdone-template` | A story exists but is missing the right template-backed structure, so you need a fast way to apply or repair the expected sections and attachment links on an existing issue. |
| `imdone-add` | You want to create a new Jira or GitHub issue with the project's usual defaults without switching back to the provider UI or manually rebuilding the same issue shape each time. |
| `backlog-refinement` | TODO stories are too vague to build, so developers and product owners need a fast way to identify weak stories and tighten them into thin, executable slices. |
| `hypothesis-driven-development` | Teams start building before they agree on the value, success criteria, demo path, or execution plan, which leads to output without proof of outcome. |
| `shared-context-report` | It is hard to tell which in-progress stories are safe to hand off or how to brief others on the work without interrupting the team because planning context is missing or uneven across the work set. |
| `markdown-pdf-docker` | Teams have markdown reports and Mermaid diagrams, but no reliable way to turn them into polished PDFs without depending on host-specific tooling. |
| `cycle-time-report` | Teams want to inspect delivery speed from archived issue history and share the result as a markdown report, trend chart, and PDF without rebuilding the numbers by hand. |

These skills are bundled in your backlog under `.claude/skills/` and `.codex/skills/`.

## Support & Feedback

Found a bug or have a feature request? We'd love to hear from you!

- **Website**: [imdone.io](https://imdone.io?utm_source=imdone-cli-readme&utm_medium=referral&utm_campaign=readme-positioning-test)
- **Email**: support@imdone.io
- **Discord**: Join our **[Imdone users group](https://discord.com/invite/FjAcxMxE)** for real-time support and discussions

---

## Commands

> **📋 Output Formats**: Many commands support the `-f, --format` option to change output format. Available formats are: `json`, `yaml`, `csv`, `text` (default).

### `init` – Initialize Issue Tracking Integration

```bash
imdone init
```

Initialize integration with Jira or GitHub Issues. You'll be prompted to select your provider and provide the necessary configuration.

**Common Options:**
- `--name` - Project name
- `--provider` - Issue tracking provider: `jira` or `github`
- `--force` - Force initialization even if `.imdone-cli.yml` exists in an ancestor directory

**Jira Options:**
- `--jira-url` - Jira instance URL
- `--jira-project-key` - Jira project key
- `--jira-username` - Jira username
- `--jira-api-token` - Jira API token
- `--jql` - JQL query for filtering issues

**GitHub Options:**
- `--github-url` - GitHub Enterprise URL (for example, `https://github.mycompany.com`)
- `--github-owner` - GitHub repository owner (auto-detected from git remote when in a git repo)
- `--github-repo` - GitHub repository name (auto-detected from git remote when in a git repo)
- `--github-token` - GitHub Personal Access Token
- `--gql` - GitHub issue query (for example, `is:issue state:open`)

**GitHub Notes:**
- `imdone pull` fetches issues, comments, and attachments from GitHub
- `imdone push` syncs issue content, labels, comments, and attachments (add/modify/delete/rename)
- `imdone add` fully supports creating GitHub issues
- GitHub owner and repo are auto-detected from your git remote origin URL
- During `imdone init`, the GitHub repository prompt accepts HTTPS and Git-style SSH repository inputs such as `https://github.com/owner/repo`, `git@github.com:owner/repo.git`, `ssh://git@github.com/owner/repo.git`, and `git+ssh://git@github.com/owner/repo.git`
- The GitHub repository prompt now shows accepted repository examples directly in the prompt, and invalid input repeats those examples in the validation message
- Token guidance: classic tokens need `repo`; fine-grained tokens need repository `Contents: Read and write`, `Issues: Read and write`, and `Pull requests: Read and write`

---

### `clone` – Clone Remote Backlog Repository

```bash
imdone clone
```

Options:
- `--remote-url`
- `--backlog-dir`
- `--github-owner`
- `--github-repo`
- `--github-token`

Clones a remote backlog repo for onboarding or setting up a new local workspace. After the backlog is cloned locally, `imdone clone` reads the cloned config and prompts only for any missing provider-specific setup values that are still needed, such as GitHub owner, repo, or token.

If the cloned `.imdone-cli.yml` is already configured for GitHub, `imdone clone` now preserves that provider instead of falling back to Jira prompts. GitHub-backed clones only ask for missing `owner`, `repo`, and `token` values after clone. Existing cloned config values and CLI flags suppress redundant prompts, and `gql` stays in the cloned config rather than being re-prompted.

---

### `update` – Update imdone-cli Config

```bash
imdone update
```

Alias: `u`

Pull imdone-cli config from `origin/main` (using "theirs" strategy).

**Options:**
- `--force` - Force the update without prompting when imdone-cli is outdated

---

### `hdd` – Launch A Coding Agent With HDD Context

```bash
imdone hdd [issueKey]
imdone hdd --setup
```

Launch Codex or Claude with a startup prompt that tells the agent to use the bundled `hypothesis-driven-development` skill for the resolved story.

By default, `imdone hdd`:

- uses the explicit `issueKey` argument when provided
- otherwise reuses the active HDD story from `backlog/.imdone/hdd-skill.yml`
- otherwise prompts for a story key
- reuses the saved default coding agent when available
- falls back to a pasteable HDD prompt when no supported coding agent is installed

Use `--setup` to force reselecting both the story key and coding agent instead of reusing the saved HDD launch context.

**Options:**
- `-s, --setup` - Force issue-key and agent setup before launch

---

### `pull` – Pull Issues from Provider

```bash
imdone pull
```

Alias: `g`

**Options:**
- `-f, --format <format>` - Output format: json, yaml, csv, text (default: text)
- `--jql [jql]` - Jira only. Temporarily override the saved Jira query for this pull run only
- `--gql [gql]` - GitHub only. Temporarily override the saved GitHub query for this pull run only

Fetches issues, comments, and attachments from your configured provider, updates the local Markdown workspace, and restores local changes when needed.

For Jira-backed projects, you can use `--jql` to temporarily broaden or change the pull scope for one run without editing `.imdone/config.yml`. This is useful for backlog refinement when you want to pull a wider set of issues and then return to your normal default sync scope on the next plain `imdone pull`.

For GitHub-backed projects, you can use `--gql` to temporarily target a specific GitHub issue or pull-request slice for one run without changing the saved default GitHub query.

If the project is configured with both Jira and GitHub providers:
- `--jql` affects only the Jira provider for that run
- `--gql` affects only the GitHub provider for that run
- you can use both in the same `imdone pull` command

**What gets pulled:**
- Issue content and metadata
- All comments (see [Working with Comments](#working-with-comments))
- All attachments (see [Working with Attachments](#working-with-attachments))
- Status and field updates

**Provider Notes:**

**GitHub:**
- Fetches issues based on state (open/closed), labels, milestones, and assignees
- Maps GitHub states to imdone lists via status configuration
- Handles pagination automatically for large repositories
- Attachments are downloaded from the dedicated `imdone-attachments` branch and linked locally
- When an issue is newly pulled and already maps to the done list, it is created directly in the archive folder if archive is configured

**Jira:**
- Uses JQL queries for flexible filtering
- Sprint and epic integration
- `imdone pull --jql "<query>"` temporarily replaces the saved Jira query for that run only, while still refreshing already-synced local Jira issues
- In mixed Jira/GitHub projects, `--jql` affects only the Jira provider's pull for that run
- When an issue is newly pulled and already maps to the done list, it is created directly in the archive folder if archive is configured

**GitHub query override examples:**

```bash
# Temporarily target one GitHub slice
imdone pull --gql 'is:pr state:open'

# Temporarily override both providers in the same run
imdone pull --jql 'project = "SCRUM" AND status != Done ORDER BY updated DESC' --gql 'is:pr state:open'
```

---

### `push` – Push Changes to Provider

```bash
imdone push
```

Alias: `p`

**Options:**
- `--rewrite-repo-links` - GitHub only. For touched issues, republish in-scope issue content and text attachments so local repo-relative markdown links are refreshed against the current source-repo web-link mapping

Lints, pulls, extracts updates, and syncs your local Markdown changes back to the provider.

**What gets pushed:**
- Issue content and metadata changes
- New comments (see [Working with Comments](#working-with-comments))
- New and modified attachments (see [Working with Attachments](#working-with-attachments))
- Labels
- Provider workflow state when the issue's local imdone list has an explicit status mapping

**Provider Notes:**

**Jira:**
- Validates markdown formatting for Jira compatibility
- Converts markdown to Jira markup automatically
- Applies mapped local-list changes as Jira workflow transitions when `.imdone/config.yml` has a matching `statuses[*].list` and `statuses[*].jira` entry

**GitHub:**
- Uses markdown natively (no conversion needed)
- Applies mapped local-list changes by using native `open`/`closed` state mappings or configured GitHub status labels/tags
- Attachments are uploaded to the dedicated `imdone-attachments` branch; local links are rewritten to the current attachment URL
- `imdone push --rewrite-repo-links` explicitly refreshes in-scope repo-relative markdown links in touched GitHub issue content and text attachments against the current source-repo web-link mapping, even when the touched content would not otherwise need republishing
- GitHub attachment add, modify, delete, and rename operations update the branch-backed current set without writing an attachment ledger comment

> **💡 Pro Tip:** Use `commentRequired:true` in task metadata to enforce comments on critical issues before pushing.

---

### `status` – Show Pending Changes

```bash
imdone status
```

Alias: `st`

Shows all files in your backlog directory that have local changes not yet pushed — tasks, comments, and attachments — grouped by operation type.

**Output:**

```
Changes in backlog/current-sprint (4 files):

  Added:
    attachment  SCRUM-200    new-plan.md

  Modified:
    task        SCRUM-123    issue-description.md
    comment     SCRUM-123    comments-SCRUM-123.md

  Deleted:
    attachment  SCRUM-456    screenshot.png
```

Each line shows the **kind** (`task`, `comment`, or `attachment`), the **issue key**, and the **filename**. If the directory is clean, it prints `Nothing to push — working directory is clean.`

---

### `add` – Create New Issue

```bash
imdone add
```

Alias: `a`

Creates a new Jira or GitHub issue either interactively or from provided options. The prompts adapt to the selected provider.

**Options:**
- `--provider [provider]` - Provider to create the issue in (`jira` or `github`)
- `--project-key [projectKey]` - Project key (e.g., `PROJ` for Jira, `owner/repo` for GitHub)
- `--template [template]` - Template to use for the issue (e.g., story, bug)
- `--issue-type [issueType]` - Issue type (Jira only: Story, Task, Bug, etc.)
- `--location [location]` - Issue location (Jira only): "backlog" or "sprint"
- `--sprint-id [sprintId]` - Sprint ID when location is "sprint" (Jira only)
- `--list-sprints` - Jira only. List active sprint names and IDs that can be used with `--sprint-id`, then exit without creating an issue
- `--list-issue-types` - Jira only. List available issue types that can be used with `--issue-type`, then exit without creating an issue
- `--summary [summary]` - Issue summary/title
- `-f, --format <format>` - Output format: json, yaml, csv, text (default: text)

**Examples:**

```bash
# Jira: Discover valid sprint IDs first
imdone add --project-key PROJ --list-sprints

# Jira: Discover valid issue types first
imdone add --project-key PROJ --list-issue-types

# Jira: Create issue with all options specified
imdone add --project-key PROJ --template story --issue-type Story --location sprint --sprint-id 123 --summary "New feature request"

# GitHub: Create issue (note: no issue-type or location needed)
imdone add --project-key owner/repo --template story --summary "Bug fix request"

# Interactive mode for any provider
imdone add
```

**Interactive prompts (when options not provided):**
1. **Template selection** - Choose from available templates in `.imdone/templates`
2. **Project selection** - Choose which project to create the issue in (only shown when multiple projects are configured)
3. **Issue type** - Select issue type (Jira only - skipped for GitHub)
4. **Location** - Choose current sprint or backlog (Jira only - skipped for GitHub)
5. **Summary** - Enter the issue title/summary

**Sprint discovery:**
If you want to script issue creation into a specific Jira sprint, run `imdone add --list-sprints` first. It prints the active sprint names and IDs for the selected Jira project, so you can copy the correct value into `--sprint-id` without opening Jira.

**Issue type discovery:**
If you want to script issue creation with an exact Jira issue type, run `imdone add --list-issue-types` first. It prints the available issue types for the selected Jira project, so you can pass the exact value into `--issue-type` without guessing.

**What gets created:**
- New issue in your provider (Jira or GitHub) with specified summary
- Markdown content based on selected template (if any)
- Basic structure (Description, Tasks) if no template is used
- Template tags automatically converted to labels (GitHub) or labels field (Jira)
- A provider-specific replay command showing how to create similar issues without prompts
- Automatic pull of the new issue into your local project

**Templates:**
If your project has templates in `.imdone/templates`, they are available during issue creation. Templates give you consistent starting structure, and tags in templates (for example `#bug` or `#urgent`) are automatically converted to labels.

Templates can also include special links that automatically create files in the issue's `attachments/` directory. See the **Auto-File Creation in Templates** section under the `template` command for details.

**💡 Replay Command:**
After creating an issue, the CLI will display the exact command to create a similar issue without prompts, tailored to your provider:

**Jira example:**
```
💡 Next time, use: imdone add --project-key "PROJ" --template "story" --issue-type "Story" --location "backlog" --summary "Your issue title"
```

**GitHub example:**
```
💡 Next time, use: imdone add --project-key "owner/repo" --template "story" --summary "Your issue title"
```

---

### `template` – Apply Template to Existing Issue

```bash
imdone template [issueKey]
```

Alias: `t`

Applies a template to an existing issue through an interactive guided flow or with explicit options.

**Arguments:**
- `[issueKey]` - Issue key to apply template to (e.g., PROJ-123)

**Options:**
- `--template [template]` - Template to apply (e.g., story, bug, dod)

**Examples:**

```bash
# Apply template with all options specified
imdone template PROJ-123 --template dod

# Interactive mode - prompts for missing arguments
imdone template

# Prompt for template only
imdone template PROJ-123
```

**Interactive prompts (when options not provided):**
1. **Issue selection** - Choose from available issues in current sprint
2. **Template selection** - Choose from available templates in `.imdone/templates`

**What gets applied:**
- Template metadata (tags, custom fields) is merged with existing metadata

**Templates:**
Templates are markdown files in `.imdone/templates` that provide consistent issue structure. Templates can reference existing issue content with `${markdown}` to keep current content in place. A default `story` template is included.

**Auto-File Creation in Templates:**
Templates can automatically create files in the issue's attachments directory using specially formatted links. This works with both `imdone add` (when creating new issues) and `imdone template` (when applying templates to existing issues).

```markdown
[Link Text](./attachments/filename.ext?template=<template_name>)
[Empty File](./attachments/filename.ext)
```

- Links with `?template=<template_name>` create files populated with content from the specified template
  - Template names can be specified with or without the `template_` prefix (e.g., `story` or `template_story`)
- Links without a template parameter create empty files
- Files are created in the issue's `attachments/` directory when the template is used
- Existing files are never overwritten
- If a template is not found, an empty file is created with a warning

**Example Template with Auto-File Creation:**
```markdown
# Story Template

## Documents
- [Story Document](./attachments/story.md?template=story)
- [Notes](./attachments/notes.md)
- [Test Plan](./attachments/test-plan.md?template=test)

## Description
Add your story description here...
```

When this template is used (either with `imdone add` or `imdone template`), the system will automatically:
1. Create the `attachments/` directory in the issue folder
2. Create `story.md` with content from the `story` template
3. Create an empty `notes.md` file
4. Create `test-plan.md` with content from the `test` template

---

### `merge` – Resolve Conflicts

```bash
imdone merge
```

After resolving conflicts manually, run this to push the resolved changes to your configured provider.

---

### `move` – Move Issue to New Status

```bash
imdone move [<ISSUE_KEY>] [<STATUS>]
```

Alias: `mv`

Moves a Jira or GitHub issue to a new status by performing the provider-specific status change. If arguments are not provided, the command will prompt for them interactively.

When moving an issue to "Done" status, the resolution field can be set automatically or interactively.

Arguments:
- `ISSUE_KEY` - The issue identifier (for example, Jira `PROJ-123` or a GitHub issue number)
- `STATUS` - The target status name (case-insensitive)

**Options:**
- `-f, --format <format>` - Output format: json, yaml, csv, text (default: text)
- `-r, --resolution <resolution>` - Set custom resolution when moving to Done (e.g., "Fixed", "Won't Do")
- `--no-resolution` - Skip setting resolution even when moving to Done
- `-p, --prompt-resolution` - Interactively select resolution from available options
- `--list-statuses` - List valid statuses for the issue without changing it
- `--list-transitions` - Alias for `--list-statuses`

**Resolution Behavior:**
- By default, moving to "Done" automatically sets resolution to "Done"
- Existing resolutions are never overwritten
- Use `--prompt-resolution` to see all available resolutions and choose interactively
- Use `--no-resolution` to skip resolution setting entirely

Examples:

```bash
# Move issue with specified arguments (auto-sets resolution to "Done")
imdone move PROJ-123 "Done"

# Move issue with custom resolution
imdone move PROJ-123 "Done" --resolution "Fixed"

# Interactive resolution selection
imdone move PROJ-123 "Done" --prompt-resolution

# Move to Done without setting resolution
imdone move PROJ-123 "Done" --no-resolution

# Move issue and output in JSON format
imdone move PROJ-123 "In Progress" --format json

# List valid statuses without changing the issue
imdone move PROJ-123 --list-statuses

# List valid statuses in structured output
imdone move PROJ-123 --list-statuses --format json

# Interactive mode - prompts for missing arguments
imdone move

# Prompt for status only
imdone move PROJ-123
```

The command automatically discovers available transitions for the issue and provides an interactive selection if the specified status is not valid. Use `--list-statuses` or `--list-transitions` when you want that discovery step without mutating the issue.

---

### `lint` – Lint Todo Comments

```bash
imdone lint
```

Checks and fixes formatting issues for compatibility with Jira.

---

### `reset` – Reset Local Project State

```bash
imdone reset
```

**Options:**
- `-f, --format <format>` - Output format: json, yaml, csv, text (default: text)

Removes Jira integration state and pulls fresh data from Jira.

---

### `clean` – Clean Project Data

```bash
imdone clean
```

Removes temporary files and data from the project without affecting the core configuration.

---

### `destroy` – Remove Integration

```bash
imdone destroy
```

Deletes the config and backlog folder. Prompts for confirmation first.

---

### `license` – Manage License

```bash
imdone license
```

Options:
- `--token`
- `-s, --show`

Examples:

```bash
imdone license --token <your-token>
imdone license --show
imdone license -s
```

---

### `show` – Show Local Issue Context

```bash
imdone show [ISSUE_KEY]
```

Alias: `s`

Shows the local shared context for one issue from your backlog repo. The default text output includes the issue title, status, tags, metadata, repo-relative paths for the issue and comments files, the attachments directory, and visible attachment filenames. If no issue key is provided, you'll be prompted to search and select from existing issues.

**Options:**
- `-f, --format <format>` - Output format: json, yaml, csv, text (default: text)

**Structured output:**
- `json` and `yaml` include the local issue-context fields for automation, including `key`, `title`, `status`, `tags`, `meta`, `issueFile`, `commentsFile`, `attachmentsDir`, and `attachments`
- `csv` flattens the same fields for shell and spreadsheet workflows

**Notes:**
- Paths are repo-relative, not absolute
- Missing comments or attachments are shown explicitly as `none` in text output and `null` / empty arrays in structured output

**Examples:**

```bash
# Interactive mode - search and select issue
imdone show

# Default text format - local shared context
imdone show PROJ-123

# Text format (explicit)
imdone show PROJ-123 --format text
imdone show PROJ-123 -f text

# JSON format - structured data for automation
imdone show PROJ-123 --format json

# YAML format - preserves Jira markup and metadata
imdone show PROJ-123 --format yaml

# CSV format - tabular data
imdone show PROJ-123 --format csv

# Interactive mode with different format
imdone show --format json
```

---

### `list` – List Local Issues

```bash
imdone list
```

Alias: `ls`

Lists all issues from your configured provider (Jira or GitHub). Uses Unix `ls`-style flags for familiar terminal behavior.

**Display Options:**
- `-l` - Long format with detailed issue information (status, assignee, type)
- `-1` - One issue per line (compact: KEY + PATH)
- `-t` - Sort by modification time (most recent first)
- `-r` - Reverse sort order
- Default format shows compact listing (KEY + PATH per line)
- Favorited issues show a ★ indicator in all views

**Filter and Output Options:**
- `--fav, --favorites` - Show only favorited issues (see `imdone favorite`)
- `--limit <number>` - Limit the number of tasks displayed (default: 0, no limit)
- `-f, --format <format>` - Output format: json, yaml, csv, text (default: text)
- `-q, --query <query>` - Filter issues using imdone filter syntax (applied locally)

**Examples:**

```bash
# Compact listing (default) - shows KEY and PATH
imdone list

# Long format with details (table view)
imdone ls -l

# Sort by time, most recent first
imdone ls -t

# Long format, sorted by time
imdone ls -lt

# Reverse the sort order (oldest first)
imdone ls -ltr

# One issue per line (same as default compact format)
imdone ls -1

# Limit to 10 most recent issues
imdone list -t --limit 10

# Show only favorited issues
imdone list --favorites
imdone ls --fav

# Favorites in long format, sorted by time
imdone ls --fav -lt

# List issues in JSON format
imdone list --format json

# List limited issues in CSV format
imdone list --limit 5 --format csv

# Filter by status
imdone ls -q 'meta.status="In Progress"'

# Filter by assignee
imdone ls -q 'meta.assignedTo="username"'

# Filter by label/tag
imdone ls -q 'tag:bug'

# Filter open issues
imdone ls -q 'meta.status="open"'

# Filter by milestone
imdone ls -q 'meta.milestone="v1.0"'

# Filter blocked issues (Jira)
imdone ls -q 'meta.blocked=*'

# Combine filters
imdone ls -q 'meta.status="open" and tag:enhancement'

# Filter pull requests (GitHub)
imdone ls -q 'meta.isPullRequest=true'
```

**imdone Filter Syntax:**

The `-q, --query` option uses imdone's filter syntax, applied locally against your synced issues. This single query language works across all providers (Jira, GitHub).

[Learn more about imdone filter syntax](https://imdone.io/docs/#/filters)

**Common filter patterns:**
- `meta.status="In Progress"` - Filter by status value
- `meta.assignedTo="username"` - Filter by assignee
- `meta.milestone="v1.0"` - Filter by milestone (GitHub)
- `meta.blocked=*` - Show blocked/flagged issues (Jira)
- `tag:bug` - Filter by tag/label
- `meta.isPullRequest=true` - Show only pull requests (GitHub)
- `meta.status="open" tag:enhancement` - Combine multiple filters

---

### `favorite` – Mark Issues as Favorites

```bash
imdone favorite [ISSUE_KEY]
```

Alias: `f`

Mark issues as favorites for quick access when working with many issues in your current sprint. Favorites are stored locally in `.imdone/favorites.yml` and are personal to your workspace.

**Arguments:**
- `[ISSUE_KEY]` - Issue key to favorite (e.g., `PROJ-123` for Jira, `42` for GitHub)

**Options:**
- `-r, --remove` - Remove issue from favorites

**Examples:**

```bash
# Mark issue as favorite
imdone favorite PROJ-123

# Interactive mode - search and select from available issues
imdone favorite

# Remove issue from favorites
imdone favorite PROJ-123 --remove
imdone favorite PROJ-123 -r

# Interactive removal - search and select from favorited issues only
imdone favorite --remove

# List only your favorite issues
imdone ls --favorites
imdone ls --fav

# Combine with other ls flags
imdone ls --fav -l      # Long format, favorites only
imdone ls --fav -t      # Favorites sorted by time
```

**How it works:**

1. **Mark as favorite**: Validates the issue exists in your current sprint and adds it to your favorites list
2. **Visual indicator**: Favorited issues show a ★ indicator in all list views
3. **Filter favorites**: Use `imdone ls --favorites` to see only your favorited issues
4. **Personal workspace**: Favorites are stored in `.imdone/favorites.yml` (git-ignored) and don't sync across team members

**When to use:**
- Working on 2-3 specific issues among many in current sprint
- Quickly filtering to your most important work items
- Reducing navigation overhead in large sprints

**Provider Support:**
- **Jira**: Use project keys like `PROJ-123`
- **GitHub**: Use issue numbers like `42`

---

### `log` – View Issue Changelog

```bash
imdone log [<ISSUE_KEY>] [--stats]
```

Shows changelog for a Jira or GitHub issue, with optional statistics. If no issue key is provided, you'll be prompted to search and select from existing issues. In mixed-provider projects, the selected or supplied issue key is resolved against local issue metadata so the changelog request is sent to the correct provider adapter.

Arguments:
- `ISSUE_KEY` - The issue identifier (optional). Use Jira keys like `PROJ-123` or GitHub issue numbers like `42`.

**Options:**
- `-s, --stats` - Show statistics for the changelog
- `-f, --format <format>` - Output format: json, yaml, csv, text (default: text)

Examples:

```bash
# Show changelog for specific issue
imdone log PROJ-123

# Show changelog for a GitHub issue
imdone log 42

# Show changelog statistics for specific issue  
imdone log PROJ-123 --stats

# Show changelog in JSON format
imdone log PROJ-123 --format json

# Show changelog statistics in YAML format
imdone log PROJ-123 --stats --format yaml

# Interactive mode - search and select issue
imdone log

# Interactive mode with statistics
imdone log --stats
```

---

### `test` – Test Configuration

```bash
imdone test
```

Validates connection and permission setup.

---

### `pause` – Pause Desktop Watcher

```bash
imdone pause
```

Pauses the [imdone desktop](https://imdone.io/docs) watcher by creating a `.imdonepause` file in the backlog directory. This prevents conflicts between CLI operations and the desktop application.

**When to use:**
- Before running extended CLI operations
- When you want to prevent desktop automatic syncing temporarily
- During manual conflict resolution

**Note:** All imdone-cli commands automatically pause the watcher during execution and resume when complete.

---

### `resume` – Resume Desktop Watcher

```bash
imdone resume
```

Resumes the [imdone desktop](https://imdone.io/docs) watcher by removing the `.imdonepause` file from the backlog directory.

**When to use:**
- After manually pausing the watcher
- If a CLI command was interrupted and didn't resume automatically

---

### `hooks` – Git Hooks Management

#### Set up automatic `imdone pull` after `git pull` and `imdone push` before `git push`

```bash
imdone hooks setup
```

Options:
- `--force` - Overwrite existing git hooks

This sets up git hooks that automatically synchronize your configured provider with git operations:

- **post-merge hook**: Runs `imdone pull` after each successful `git pull` to fetch the latest provider issues
- **pre-push hook**: Runs `imdone push` before each `git push` to ensure your local issue changes are synchronized

#### Remove git hooks

```bash
imdone hooks remove
```

Removes git hooks that were set up by imdone-cli.

**How it works:**
- Creates `post-merge` and `pre-push` hooks in `.git/hooks/`
- The hooks detect if the current directory has imdone configuration
- **post-merge**: Automatically runs `imdone pull` after successful git merges (which happen during `git pull`)
- **pre-push**: Automatically runs `imdone push` before `git push` operations
- The pre-push hook will cancel the push if `imdone push` fails (use `git push --no-verify` to bypass)
- Only runs for actual merges, not rebases
- Gracefully handles cases where imdone-cli is not available

---

## Status Mapping

Status mapping applies to both Jira and GitHub. Configure the local list and provider mapping together in `.imdone/config.yml`:

```yaml
code:
  include_lists:
    - TODO
    - DOING
    - REVIEW
    - DONE
lists:
  - name: TODO
    hidden: false
    ignore: false
  - name: DOING
    hidden: false
    ignore: false
  - name: REVIEW
    hidden: false
    ignore: false
  - name: DONE
    hidden: false
    ignore: true
settings:
  plugins:
    JiraPlugin:
      providers:
        - jira
        - github
      statuses:
        - jira: To Do
          github: open
          list: TODO
        - jira: In Progress
          github: in_progress
          list: DOING
        - jira: Code Review
          github: code-review
          list: REVIEW
        - jira: Done
          github: closed
          list: DONE
```

Use the `list` value for the local imdone board column. Use `jira` for Jira workflow status names and `github` for GitHub states or workflow labels like `code-review`.

How the mapping is used:

- `imdone pull` reads provider state and chooses the local list. For GitHub, a configured workflow label/tag such as `code-review` wins before the normal `open`/`closed` fallback, and that label/tag is stored in local `status` metadata.
- `imdone push` reads the local list and updates provider state. Jira issues transition to the mapped Jira status. GitHub issues move to the mapped `open`/`closed` state or configured workflow label/tag, and stale configured workflow labels/tags are removed. Unmapped lists leave provider workflow state unchanged.

For Jira projects with custom workflows, exact workflow status names such as `Code Review` can map to their own local list before imdone falls back to the Jira status category. For GitHub projects, engineers can apply a label such as `code-review` when they want that workflow state reflected in the imdone list.

---

## GitHub Integration

imdone-cli fully supports GitHub Issues as an alternative to Jira. This allows teams using GitHub to benefit from the same context-driven development workflow.

### Supported Features

- `imdone init` with GitHub provider selection
- `imdone pull` to fetch GitHub issues, comments, and attachments into local markdown files
- `imdone push` to sync local changes back to GitHub (content, comments, and attachments)
- `imdone add` to create new GitHub issues with template support
- `imdone ls` to list GitHub issues with custom queries
- `imdone template` to apply templates to GitHub issues
- Comment synchronization (via `imdone pull` and `imdone push`)
- **Attachment synchronization** — add, modify, delete, and rename attachments locally; changes sync bidirectionally
- Auto-detection of GitHub owner/repo from git remote origin
- Status mapping (open/closed → TODO/DOING/DONE)
- Optional label-based status mapping for GitHub workflow labels like `code-review`
- Label support (template tags automatically converted to labels)

### Getting Started with GitHub

1. **Initialize with GitHub:**
   ```bash
   imdone init
   # Select "github" when prompted for provider
   ```

2. **GitHub automatically detects your repository:**
   - Owner and repo are extracted from your git remote origin URL
   - Supports HTTPS and Git-style SSH remote URLs, including `git@github.com:owner/repo.git`, `ssh://git@github.com/owner/repo.git`, and `git+ssh://git@github.com/owner/repo.git`

3. **If you enter the repository URL manually during `imdone init`:**
   - The prompt shows accepted examples for HTTPS and SSH forms up front
   - Invalid input repeats those accepted examples instead of implying HTTP-only setup

4. **Provide your GitHub Personal Access Token:**
   - Create a classic token at: https://github.com/settings/tokens/new?scopes=repo
   - Or create a fine-grained token with repository `Contents: Read and write`, `Issues: Read and write`, and `Pull requests: Read and write`
   - Under Repository access, choose **Only select repositories**, then confirm your target repo appears under **Selected repositories** before you generate the token
   - If GitHub still shows 0 selected repositories, re-select the repo there or use a classic token instead
   - Token is stored securely in `.env` file

5. **Pull your GitHub issues:**
   ```bash
   imdone pull
   ```

### GitHub-Specific Features

**Query Syntax:**
GitHub uses a simplified query syntax (not JQL):
- `is:open` - Open issues
- `is:closed` - Closed issues
- `label:bug` - Issues with "bug" label
- `milestone:v1.0` - Issues in "v1.0" milestone
- `assignee:username` - Issues assigned to specific user

**Directory Structure:**
Same as Jira — each issue gets its own folder, including an `attachments/` subdirectory:
```
backlog/
├── current-sprint/
│   ├── 1-Fix_login_bug/
│   │   ├── attachments/
│   │   │   ├── screenshot.png
│   │   │   └── .metadata.yml
│   │   ├── comments-1.md
│   │   └── issue-1.md
│   └── 2-Add_dashboard/
│       ├── attachments/
│       └── issue-2.md
```

#### Pull Request (PR) Support

When syncing issues from GitHub, imdone automatically detects pull requests and provides special handling:

- **Directory Naming**: PRs get a `PR-` prefix in their directory names for easy visual identification:
  - Regular issue: `123-my-issue-title/`
  - PR issue: `PR-456-fix-bug/`

- **PR Metadata**: Local-only metadata fields are added to PR issues (filtered from push to GitHub):
  - `isPullRequest` - Boolean, true if the issue is a PR
  - `prSourceBranch` - Source branch name (e.g., `feature/my-feature`)
  - `prTargetBranch` - Target branch name (e.g., `main`)
  - `prMergedAt` - Merge timestamp (ISO 8601) if the PR was merged

- **Filtering PRs**: Use the `ls` command with metadata filters:
  ```bash
  # List all PRs
  imdone ls meta.isPullRequest=true
  
  # List merged PRs only
  imdone ls meta.prMergedAt=*
  
  # Filter by source branch
  imdone ls meta.prSourceBranch=feature/my-feature
  
  # Filter by target branch
  imdone ls meta.prTargetBranch=main
  ```

#### Reactions Metadata

GitHub issue reactions are synced as individual metadata fields (local-only, filtered from push):

| Metadata Field    | Description              |
| ----------------- | ------------------------ |
| `reactionThumbsUp`   | 👍 +1 reactions count   |
| `reactionThumbsDown` | 👎 -1 reactions count   |
| `reactionLaugh`      | 😄 laugh reactions     |
| `reactionHooray`     | 🎉 hooray reactions    |
| `reactionConfused`   | 😕 confused reactions  |
| `reactionHeart`      | ❤️ heart reactions     |
| `reactionRocket`     | 🚀 rocket reactions    |
| `reactionEyes`       | 👀 eyes reactions      |
| `reactionTotal`      | Total reaction count   |

Filter by reactions:
```bash
# Issues with 5+ thumbs up
imdone ls meta.reactionThumbsUp=5..

# Issues with any heart reactions
imdone ls meta.reactionHeart=1..

# Issues with any reactions at all
imdone ls meta.reactionTotal=1..
```

#### Jira-Specific Metadata

Jira issues include additional metadata fields synced from Jira custom fields:

| Metadata Field | Description                                     | Example Value  |
| -------------- | ----------------------------------------------- | -------------- |
| `blocked`      | Flagged/Blocked field value from Jira           | `Impediment`   |
| `epic`         | Epic link (parent epic key)                     | `PROJ-100`     |
| `rank`         | Jira ranking field for issue ordering           | `0|i00007:`    |
| `statusName`   | Exact Jira workflow status for custom workflows | `Code Review` |

For engineers working in Jira projects with custom workflows, `statusName` keeps the exact workflow state visible in the local issue file. The existing `status` metadata remains the Jira status category, and `statusName` is not written into provider-side issue body metadata.

**Blocked Field:**
- Automatically detected from Jira "Flagged" or "Blocked" custom fields
- Value can be any string set in Jira (e.g., "Impediment", "Blocked", "Yes")
- Used by shared-context reports to identify blockers and provide unblock advice

Filter by Jira-specific fields:
```bash
# Show all blocked/flagged issues
imdone ls -q 'meta.blocked=*'

# Filter by epic
imdone ls -q 'meta.epic=PROJ-100'
```


### GitHub vs Jira Feature Comparison

| Feature | Jira | GitHub |
|---------|------|--------|
| Pull issues | ✅ | ✅ |
| Push changes | ✅ | ✅ |
| Comments | ✅ | ✅ |
| Attachments (pull) | ✅ | ✅ |
| Attachments (push: add/modify/delete/rename) | ✅ | ✅ |
| Attachment link rewriting | ✅ | ✅ |
| Custom fields | ✅ | ❌ Not supported |
| Sprints | ✅ | ❌ Use milestones |
| Issue types | ✅ | ❌ Use labels |
| Epics | ✅ | ❌ Use milestones |

### GitHub Attachments

GitHub doesn't have a native attachments API, so imdone-cli uses a dedicated **`imdone-attachments` branch** to give you the same local attachment workflow you get with Jira.

**How it works:**

- **Storage**: Files are stored on a dedicated branch named `imdone-attachments`, under a top-level `_imdone-attachments/` folder with stable per-issue paths such as `_imdone-attachments/{issueNumber}/{filename}`.
- **Branch-backed current set**: `imdone pull` reads the current attachment list from the branch tree/Contents API. GitHub issue comments are not used as an attachment ledger and new machine-readable attachment comments are not posted.
- **Stable content updates**: When an attachment's content changes but its filename does not, imdone updates the existing branch-backed file path and uses GitHub's content SHA for change detection and concurrency protection.
- **Rename/delete cleanup**: When a GitHub attachment is renamed or deleted locally, `imdone push` removes the old stable path from the `imdone-attachments` branch so the old filename does not reappear on the next pull.
- **History**: Attachment history comes from GitHub branch commits for `_imdone-attachments/{issueNumber}/{filename}`.
- **Link rewriting**: Local links like `[plan.md](./attachments/plan.md)` are automatically converted to the current GitHub attachment URL on push, and back to local paths (original filename) on pull — exactly like Jira.
- **Explicit repo-link refresh**: `imdone push --rewrite-repo-links` is the GitHub escape hatch when you want touched issue content and in-scope text attachments republished so repo-relative markdown links resolve to the current source repo web URLs.

**Required token permissions:**

Your GitHub Personal Access Token must include either the classic `repo` scope or, for a fine-grained token, repository `Contents: Read and write`, `Issues: Read and write`, and `Pull requests: Read and write`. For fine-grained tokens, Repository access must also include the target repo, and you should confirm the repo appears under GitHub's Selected repositories list before generating the token. If GitHub still shows 0 selected repositories, re-select the repo there or use a classic token. imdone needs these permissions to read and update issues/comments, access PR-backed cards, and create or update attachment files in the `imdone-attachments` branch.

**Example workflow:**

```bash
# Pull issues and their existing attachments
imdone pull

# Add a planning doc
cp ~/Desktop/plan.md backlog/current-sprint/1-Fix_login_bug/attachments/

# Push — uploads the file to the attachments branch
imdone push
# ✓ Uploaded: 1/plan.md → https://github.com/owner/repo/blob/imdone-attachments/_imdone-attachments/1/plan.md
# (locally the link stays as ./attachments/plan.md)

# Modify an attachment and push again
# (updates the current branch-backed file path; sibling links stay stable)
imdone push
# ✓ Updated: 1/plan.md

# If repo-relative markdown links need to be republished against the current source repo mapping
imdone push --rewrite-repo-links
# ✓ Rewrote touched repo-relative links to current source repo web URLs
```

---

### Example Workflow

```bash
# 1. Initialize with GitHub
imdone init

# 2. Pull open issues
imdone pull

# 3. Edit issues in your editor
code backlog/current-sprint/

# 4. Sync changes
imdone push
```

---

## Markdown Formatting Guide

The imdone-cli includes automatic markdown formatting to ensure consistency across your project files. When you run `imdone lint` or `imdone push`, the following formatting rules are applied:

### Formatting Rules

#### List Indentation
- **All lists**: Uses 4 spaces per indentation level for consistent formatting
- **Ordered lists**: Uses 4 spaces per indentation level
- **Unordered lists**: Uses 4 spaces per indentation level
- **Mixed lists**: All nested lists maintain the 4-space indentation standard
- Inconsistent indentation will be automatically fixed

Example of proper list formatting:
```markdown
1. First ordered item
    - First unordered subitem (4 spaces)
        - Nested unordered item (8 spaces)
            - Deeper nested item (12 spaces)
2. Second ordered item
    - Another unordered subitem (4 spaces)
```

#### Code Blocks
- All code blocks must use fenced style with triple backticks (```)
- Code block indentation is normalized:
  - Fence markers (```) are moved to the left margin
  - Content within code blocks is reduced the same number of spaces as the fence indentation

#### Emphasis and Strong Styling
- **Emphasis** (italics): Use asterisks `*like this*` instead of underscores
- **Strong** (bold): Use double asterisks `**like this**` instead of underscores

#### Rules Not Enforced
- Line length: No maximum line length is enforced
- Bare URLs: URLs without formatting are allowed
- Trailing punctuation: Headings can end with punctuation marks

#### Additional markdownlint Rules
All default [markdownlint rules](https://github.com/DavidAnson/markdownlint/blob/main/schema/.markdownlint.yaml) are applied except for the overrides listed above. These include:
- Consistent heading styles
- Proper spacing
- List formatting
- And many other standard markdown best practices

### How Violations Are Fixed

When you run `imdone lint` or as part of `imdone push`:

1. List indentation is automatically fixed
2. Code block indentation is normalized
3. markdownlint runs to fix remaining issues
4. All fixed content is saved back to your files

All fixes are applied automatically so you don't need to manually correct formatting issues. This ensures that markdown files remain consistently formatted across your project and compatible with Jira integration.

---

## Detailed Documentation

### Working with Comments

You can add comments to issues directly from your markdown files. Comments are automatically synchronized when you run `imdone push`.

**How to add a comment:**

1. Open the `comments-<ISSUE_KEY>.md` file for the issue you want to comment on
   - **Jira:** `comments-SCRUM-31.md`
   - **GitHub:** `comments-1.md` (issue number)
2. Add your comment in markdown format between the first line and the first `---` separator
3. Run `imdone push` to sync the comment to your provider

**Example (Jira):**

```markdown
# #TODO Comments: SCRUM-31 Enhance markdown to JIRA conversion

This is my new comment! I can use **bold**, _italic_, and other markdown formatting.

The comment supports multiple lines and will be converted to Jira markup automatically.

---

### Comment 10173 by Jesse Piascik (jpiascik) on 2025-07-22T08:57:41.151-0400

Here's another comment

---
```

**Example (GitHub):**

```markdown
# #TODO Comments: 1 Test issue

This is my new comment! I can use **bold**, _italic_, and other markdown formatting.

GitHub uses markdown natively, so no conversion is needed.

---

### Comment 3832629667 by piascikj (piascikj) on 2026-02-02T02:48:59Z

Here's another comment

---
```

After running `imdone push`, your comment will be posted to the issue and the file will be updated to prevent duplicate posting.

**Notes:**
- Comments use markdown formatting
- **Jira:** Markdown is automatically converted to Jira markup
- **GitHub:** Markdown is used natively (no conversion)
- Only add content between the title line and the first `---` separator

#### Requiring Comments for Tasks

You can enforce that certain tasks must have a comment before they can be pushed to your provider by adding `commentRequired:true` to the task's metadata.

**Example task with required comment (Jira):**

```markdown
# #TODO Fix critical login bug

This task will require a comment before it can be pushed.

<!--
jira:PROJ-123
commentRequired:true
-->
```

**Example task with required comment (GitHub):**

```markdown
# #TODO Fix critical login bug

This task will require a comment before it can be pushed.

<!--
github:1
commentRequired:true
-->
```

**How it works:**

1. When you run `imdone push`, the CLI checks if any tasks have `commentRequired:true` in their metadata
2. If a required comment is missing, you'll be prompted to enter one:
   ```
   Comment required for task "Fix critical login bug" (PROJ-123): 
   ```
3. The comment is automatically added to the corresponding `comments-PROJ-123.md` file
4. The push operation continues normally, syncing both the task and the new comment to Jira

**When to use:**
- Critical bugs that need explanation
- Complex features requiring documentation
- Tasks that affect multiple team members
- Any work item that benefits from context or reasoning

### Working with Attachments

Imdone CLI automatically synchronizes attachments between your provider (Jira or GitHub) and your local project, making it easy to access files, images, and documents related to your issues without switching to the browser.

**Automatic Download During Pull:**

When you run `imdone pull`, all attachments are automatically downloaded to local `attachments/` folders within each issue directory:

```
current-sprint/
├── PROJ-123-Fix_login_bug/        # Jira
│   ├── attachments/
│   │   ├── error-screenshot.png
│   │   ├── debug-log.txt
│   │   └── .metadata.yml
│   ├── comments-PROJ-123.md
│   └── issue-PROJ-123.md
├── 1-Fix_login_bug/               # GitHub
│   ├── attachments/
│   │   ├── plan.md
│   │   └── .metadata.yml
│   ├── comments-1.md
│   └── issue-1.md
```

**What gets downloaded:**
- All attachment types: images, documents, logs, screenshots, etc.
- Original filenames are preserved
- File metadata is tracked in `.metadata.yml` for efficient synchronization
- Only new or changed attachments are downloaded on subsequent pulls

**Attachment Features:**

1. **Intelligent Sync**: Only downloads attachments that are new or have changed since the last pull
2. **Metadata Tracking**: Maintains local metadata to avoid unnecessary re-downloads
3. **Error Handling**: Gracefully handles download failures without stopping the pull process
4. **Link Rewriting**: Local links (`[plan.md](./attachments/plan.md)`) are automatically converted to provider URLs on push, and back to local links on pull

**Accessing Attachments:**

Once downloaded, attachments are available in your local file system:
- View images directly in your IDE or file explorer
- Open documents with your preferred applications
- Reference attachments in issue markdown using relative links — they will be rewritten automatically

**Editing Attachments Locally:**

You can add, modify, delete, or rename attachments directly in your local file system. When you run `imdone push`, these changes are automatically synchronized back to your provider:

1. **Add a new attachment**: Copy a file into the issue's `attachments/` folder
   - `imdone push` uploads the file and tracks it in `.metadata.yml`
   - **GitHub**: uploaded to the `imdone-attachments` branch at `_imdone-attachments/{issue}/{filename}`

2. **Modify an attachment**: Edit the file locally (e.g., update a screenshot, revise a document)
   - `imdone push` uploads the modified file as a new version
   - **Jira**: old version is preserved (no delete attempt to avoid 403 errors)
   - **GitHub**: the existing stable branch path is updated using GitHub's content SHA
   - Safety: if upload fails, the old version is preserved

3. **Delete an attachment**: Remove the file from the `attachments/` folder
   - **Jira**: `imdone push` marks the attachment as deleted with a provider comment and adds it to your local ignored list so it won't be re-downloaded on pull
   - **GitHub**: `imdone push` removes the stable file path from the `imdone-attachments` branch

4. **Rename an attachment**: Rename the file in the `attachments/` folder
   - **Jira**: `imdone push` uploads the new name, records the rename with a provider comment, and adds the old name to your ignored list
   - **GitHub**: `imdone push` writes the new stable branch path and deletes the old branch path

**Example Workflows:**

```bash
# Jira — Add a new attachment
imdone pull
cp ~/Desktop/architecture-diagram.png backlog/current-sprint/PROJ-123/attachments/
imdone push
# ✓ Added: PROJ-123/architecture-diagram.png (256KB)

# GitHub — Add a new attachment
imdone pull
cp ~/Desktop/plan.md backlog/current-sprint/1-Fix_login_bug/attachments/
imdone push
# ✓ Uploaded: 1/plan.md → https://github.com/owner/repo/blob/imdone-attachments/_imdone-attachments/1/plan.md

# Modify an existing attachment (works for Jira and GitHub)
open backlog/current-sprint/1-Fix_login_bug/attachments/plan.md
# (make your edits and save)
imdone push
# ✓ Updated: 1/plan.md

# Delete an attachment
rm backlog/current-sprint/1-Fix_login_bug/attachments/old-notes.md
imdone push
# ✓ Deleted: 1/old-notes.md

# Rename an attachment
mv backlog/current-sprint/1-Fix_login_bug/attachments/draft.md backlog/current-sprint/1-Fix_login_bug/attachments/final.md
imdone push
# ✓ Renamed: 1/draft.md → final.md
```

**Example Directory Structure:**

```
backlog/current-sprint/
├── SCRUM-31-Enhance_markdown_conversion/   # Jira issue
│   ├── attachments/
│   │   ├── my-profile-image.jpeg
│   │   ├── requirements-document.pdf
│   │   └── .metadata.yml
│   ├── comments-SCRUM-31.md
│   └── issue-SCRUM-31.md
├── 42-Add_GitHub_attachments/              # GitHub issue
│   ├── attachments/
│   │   ├── design.png
│   │   └── .metadata.yml
│   ├── comments-42.md
│   └── issue-42.md
```

**Technical Notes:**
- The `.metadata.yml` file tracks sync status and shouldn't be manually edited
- **Safety mechanism**: New version is uploaded first; old version is only replaced if the upload succeeds
- **GitHub**: Attachments are stored on a dedicated `imdone-attachments` branch under `_imdone-attachments/<issue>/...`
- **GitHub**: Stable branch paths use the local filename; content SHA protects updates from stale writes
- **GitHub**: The branch current set determines which attachments pull locally; issue comments are not used as an attachment ledger

### Customizing Your JQL Query

You can customize which Jira issues are pulled by modifying the JQL (Jira Query Language) in your project configuration:

**Location:** `.imdone/config.yml`

```yaml
plugins:
  imdone-jira:
    jql: 'project = "YOUR-PROJECT" AND status != Done ORDER BY rank ASC'
```

**Common JQL examples:**

```yaml
# Pull only issues assigned to you
jql: 'project = "PROJ" AND assignee = currentUser() AND status != Done ORDER BY rank ASC'

# Pull issues from specific sprint
jql: 'project = "PROJ" AND sprint in openSprints() ORDER BY rank ASC'

# Pull issues by labels
jql: 'project = "PROJ" AND labels in ("frontend", "backend") ORDER BY rank ASC'

# Pull issues from multiple projects
jql: 'project in ("PROJ1", "PROJ2") AND status != Done ORDER BY rank ASC'

# Pull only high priority issues
jql: 'project = "PROJ" AND priority in ("High", "Highest") ORDER BY rank ASC'
```

**Tips:**
- Use Jira's Query Builder in the web interface to test your JQL before adding it to config
- The `ORDER BY rank ASC` clause ensures issues appear in your backlog priority order
- After changing JQL, run `imdone reset` to refresh your local issues with the new query
- You can use Jira functions like `currentUser()`, `openSprints()`, and `now()`

### Temporary JQL Override For Pull

If you only need a broader Jira working set for one pull run, you do not need to edit your saved config.

```bash
# Pull a broader set for backlog refinement one time
imdone pull --jql 'project = "PROJ" AND status != Done ORDER BY updated DESC'

# Next plain pull goes back to the saved default query
imdone pull
```

Use this when you want to do temporary refinement or research against a wider Jira issue set but keep your day-to-day sync scope unchanged. In mixed-provider projects, GitHub still pulls with its configured default query.

---

## imdone-cli and Git

Imdone CLI uses git to make it easier for the rest of your team to get the project configured. Git is also used to track changes to your backlog files, so you can resolve conflicts and easily revert to previous versions if needed.

In most cases, you should let `imdone-cli` handle Git operations for you. It's designed to commit and sync changes safely so you can stay focused on your work.

If you run into a Git conflict, just resolve it in your editor, then run `imdone merge`.

### Automatic Branch Switching

To prevent accidental commits to the shared default branch (`main`), imdone-cli automatically manages branches in your backlog repository:

- **Working Branch**: All backlog modifications happen on the `imdone-work` branch
- **Automatic Creation**: The `imdone-work` branch is created automatically on first use
- **Seamless Switching**: If you're on `main`, commands like `pull`, `push`, `add`, `update`, `merge`, `move`, and `reset` will automatically switch to `imdone-work`
- **Visual Feedback**: You'll see a message when the branch switch happens: `Switched to working branch 'imdone-work'`

**Special Cases:**
- `imdone init` and `imdone clone` commit initial setup to `main` branch first, then subsequent operations automatically switch to `imdone-work`
- This ensures the foundational repository structure lives on the shared branch while all work happens on your working branch

**Benefits:**
- Prevents merge conflicts when multiple team members work simultaneously
- Keeps the default branch clean and stable
- Makes collaboration smoother and safer

---

## Attachment Versioning

imdone-cli handles attachment modifications safely to avoid permission errors when working with files created by other team members.

### How It Works

**Jira:**
When you modify an attachment that was created by another user:
- A new version is uploaded (no 403 errors)
- The old version is **preserved** in Jira (not deleted)
- Your local filesystem only keeps the current version
- Metadata tracks all versions for reference

**GitHub:**
When you modify an attachment:
- The stable branch-backed file is updated at `_imdone-attachments/{issue}/plan.md`
- GitHub's content SHA is used to detect stale writes
- Your local file stays at `./attachments/plan.md`

### Multiple Versions

If multiple team members modify the same attachment:
- **Jira**: Each upload creates a new version; all versions are visible in the Jira UI; on pull, only the most recent version is downloaded locally
- **GitHub**: The stable branch path is updated with SHA protection. If another user changed the file first, GitHub rejects the stale write instead of silently overwriting it

### Deleted and Renamed Attachments

**Team Sync:**

When you delete or rename an attachment, imdone keeps each provider's current attachment set aligned:

**When you delete an attachment locally:**
```bash
rm attachments/old-doc.pdf
imdone push
```
- The file is removed from your local filesystem
- **Jira**: The attachment remains in Jira (no delete attempt — avoids 403 errors)
- **GitHub**: The stable branch path is deleted from `imdone-attachments`
- Jira deletes are added to your local ignored list so they won't be re-downloaded on pull
- GitHub deletes disappear from the branch current set, so team members stop pulling the old file

**When you rename an attachment:**
```bash
mv attachments/doc.pdf attachments/doc-v2.pdf
imdone push
```
- New attachment `doc-v2.pdf` is uploaded
- **Jira**: Old attachment `doc.pdf` remains in Jira and the old name is added to your ignored list
- **GitHub**: Old branch path `doc.pdf` is deleted and the new branch path `doc-v2.pdf` becomes current
- Team members pull the provider's current attachment set

**Automatic Synchronization:**

When any team member runs `imdone pull`:
1. Jira comments are parsed for delete/rename events where Jira needs the ignored-list workflow
2. GitHub reads the current attachment files from the `imdone-attachments` branch
3. Only current attachments are downloaded
4. Everyone stays in sync automatically

### Manual Cleanup

Old Jira versions are **not** automatically deleted from Jira. This prevents:
- Permission errors (no delete permission needed)
- Accidental data loss
- Team conflicts over attachment ownership

**To clean up old versions:**
- **Jira**: Manually delete old attachment versions from the Jira UI
- **GitHub**: Current attachments are the files present under `_imdone-attachments/{issue}/`; rename/delete cleanup removes old stable paths automatically

### Metadata Format

Attachments are tracked in `attachments/.metadata.yml` with a filename-keyed structure:

```yaml
attachments:
  document.pdf:
    current: "12346"  # Most recent version ID
    versions:
      - id: "12346"
        filename: "document.pdf"
        size: 1500
        created: "2025-01-16T14:00:00Z"
        author:
          displayName: "User B"
          accountId: "..."
      - id: "12345"
        filename: "document.pdf"
        size: 1000
        created: "2025-01-15T10:00:00Z"
        author:
          displayName: "User A"
          accountId: "..."
ignored:
  - id: "12347"
    filename: "old-file.png"
    reason: "deleted"
    author: "user@example.com"
    timestamp: "2025-02-25T10:00:00Z"
```

**Auto-migration:** Old metadata formats are automatically migrated to the new format on first use. No data loss occurs during migration.

---

## Troubleshooting

### Invalid License

Check your token:

```bash
imdone license --show
```

### Jira Connection Issues

Ensure:
- Jira URL is correct
- API token is valid
- You have permissions

### Branch Issues

**Stuck on the wrong branch:**

If you find yourself on the `main` branch in your backlog directory, just run any imdone command and it will automatically switch you to `imdone-work`:

```bash
cd backlog
git branch  # Shows you're on 'main'
imdone pull  # Automatically switches to 'imdone-work' and continues
```

**Want to see which branch you're on:**

```bash
cd backlog
git branch
```

The current branch will be marked with an asterisk (*).

**Merge conflicts:**

If you encounter merge conflicts in your backlog repository:

1. Resolve conflicts in your editor
2. Stage the resolved files: `git add .`
3. Run: `imdone merge`

The automatic branch switching prevents most conflicts, but if multiple people work on the same issue simultaneously, conflicts can still occur.

### Debug Mode

```bash
imdone-debug pull > debug.log
```

Use for support diagnostics.
