DEV Community

Jesse PiaΕ›cik
Jesse PiaΕ›cik

Posted on

Stop Context-Switching: Edit Jira Attachments Like Code (Imdone CLI 0.39.0)

Expanding brain - jira attachments

The Problem: You're deep in flow. You need to update a screenshot in a Jira issue. Now you have to:

  1. Stop what you're doing
  2. Find the issue in your browser (which tab was it?)
  3. Scroll to attachments
  4. Upload the new version
  5. Delete the old version
  6. Try to remember what you were doing

10 minutes gone. Flow state destroyed.

What if attachments were just... files?

That's what Imdone CLI 0.39.0 does. Attachments live in your repo alongside your code. Edit them like any other file. Push changes like you push code.

The New Workflow

Before: The Browser Dance πŸ’€

# You're working on PROJ-123
vim src/auth.js
# "Oh, I need to update that architecture diagram..."

# Switch to browser
# Open Jira
# Find issue PROJ-123
# Scroll down... down... down to attachments
# Click "Attach files"
# Find the file on your computer
# Upload
# Wait for upload
# Scroll back to attachments
# Click delete on old version
# Confirm deletion
# Finally, back to your editor

# What was I doing again?
Enter fullscreen mode Exit fullscreen mode

After: Stay in Your Workflow ✨

# You're working on PROJ-123
vim src/auth.js
# "Oh, I need to update that architecture diagram..."

# Edit the diagram right there
open backlog/current-sprint/PROJ-123/attachments/architecture.png
# Make your changes, save

# Push to Jira
imdone push
# βœ“ Updated: PROJ-123/architecture.png (256KB)

# Back to coding
vim src/auth.js
# Flow unbroken
Enter fullscreen mode Exit fullscreen mode

What's New in 0.39.0

1. Modify Attachments

Edit a file locally. Push syncs the new version to Jira and deletes the old one.

imdone pull
# Edit the file
vim backlog/current-sprint/PROJ-123/attachments/screenshot.png
# Push changes
imdone push
# βœ“ Updated: PROJ-123/screenshot.png (125KB)
Enter fullscreen mode Exit fullscreen mode

Safety First: Uses an upload-then-delete pattern. If the upload fails, your old version is preserved in Jira. No data loss on network failures.

2. Delete Attachments

Remove a file locally. Push deletes it from Jira.

rm backlog/current-sprint/PROJ-123/attachments/old-design.pdf
imdone push
# βœ“ Deleted: PROJ-123/old-design.pdf
Enter fullscreen mode Exit fullscreen mode

3. Rename Attachments

Rename a file. Push handles the cleanup automatically.

cd backlog/current-sprint/PROJ-123/attachments/
mv draft-v1.png final-design.png
cd -
imdone push
# βœ“ Renamed: PROJ-123/draft-v1.png β†’ final-design.png
Enter fullscreen mode Exit fullscreen mode

Behind the scenes: Deletes old attachment from Jira, uploads the renamed file as new.

4. Add New Attachments

Drop a file in the attachments folder. Push uploads it.

cp ~/Desktop/error-log.txt backlog/current-sprint/PROJ-123/attachments/
imdone push
# βœ“ Added: PROJ-123/error-log.txt (45KB)
Enter fullscreen mode Exit fullscreen mode

Technical Deep Dive

Git-Aware Detection

The tricky part: Imdone CLI runs imdone pull before imdone push to ensure you're synced. But the pull operation includes a git stash/pop cycle:

  1. User deletes attachment locally
  2. Push calls pull
  3. Pull stashes the deletion
  4. Pull fetches from Jira (might re-download the attachment!)
  5. Pull pops the stash
  6. Push needs to detect the deletion

Solution: Capture git status before the pull operation. Use that pre-analyzed status to detect deleted/renamed attachments, even if pull re-downloaded them.

// Capture status before pull
const preAnalyzedStatus = await status(projectPath, [defaultDirectory]);

// Pull from Jira (might re-download deleted attachments)
await pull({ ...deps, providerPlugin });

// Use pre-analyzed status to detect deletions
const { result } = await _push({ ...deps, preAnalyzedStatus });
Enter fullscreen mode Exit fullscreen mode

Upload-Then-Delete Safety

When modifying attachments, the order matters:

async function replaceAttachment(issueKey, oldAttachmentId, newFilePath) {
  // 1. Upload first
  const newAttachment = await uploadAttachment(issueKey, newFilePath);

  // 2. Only delete if upload succeeded
  try {
    await deleteAttachment(oldAttachmentId);
  } catch (error) {
    logger.warn(`Uploaded new but failed to delete old: ${error}`);
    // User has duplicate in Jira, but no data loss
  }

  return newAttachment;
}
Enter fullscreen mode Exit fullscreen mode

If the upload fails, the old version stays in Jira. No data loss.

Metadata Tracking

Attachments are tracked in .metadata.yml files:

attachments:
  "12345":
    id: "12345"
    filename: "screenshot.png"
    localPath: "screenshot.png"
    size: 45678
    lastModified: "2026-01-15T10:30:00Z"
Enter fullscreen mode Exit fullscreen mode

This enables:

  • Detecting which files are new vs. modified
  • Mapping local files to Jira attachment IDs
  • Avoiding unnecessary re-downloads on pull
  • Cleaning up orphaned attachments

Getting Started

Installation

npm install -g imdone-cli@0.39.0
Enter fullscreen mode Exit fullscreen mode

Basic Workflow

# Initialize in your repo
imdone init

# Pull issues and attachments
imdone pull

# Your attachments are now local files:
# backlog/
# └── current-sprint/
#     └── PROJ-123/
#         β”œβ”€β”€ attachments/
#         β”‚   β”œβ”€β”€ screenshot.png
#         β”‚   β”œβ”€β”€ error-log.txt
#         β”‚   └── .metadata.yml
#         └── issue-PROJ-123.md

# Edit any attachment
open backlog/current-sprint/PROJ-123/attachments/screenshot.png
# (make your changes)

# Push changes back to Jira
imdone push
# βœ“ Updated: PROJ-123/screenshot.png (125KB)
Enter fullscreen mode Exit fullscreen mode

Full Feature Demo

# Pull latest
imdone pull

# Add a new attachment
cp ~/Desktop/architecture.png backlog/current-sprint/PROJ-456/attachments/

# Modify an existing one
vim backlog/current-sprint/PROJ-123/attachments/bug-report.txt

# Rename another
mv backlog/current-sprint/PROJ-789/attachments/draft.pdf backlog/current-sprint/PROJ-789/attachments/final.pdf

# Delete an outdated one
rm backlog/current-sprint/PROJ-111/attachments/old-screenshot.png

# Push all changes at once
imdone push
# βœ“ Added: PROJ-456/architecture.png (256KB)
# βœ“ Updated: PROJ-123/bug-report.txt (12KB)
# βœ“ Renamed: PROJ-789/draft.pdf β†’ final.pdf
# βœ“ Deleted: PROJ-111/old-screenshot.png
Enter fullscreen mode Exit fullscreen mode

Why This Matters

Attachments belong with your code, not in browser tabs.

When you're fixing a bug, you need:

  • The code
  • The issue description
  • The error logs
  • The screenshots

Having them scattered across your IDE and browser is cognitive overhead. Having them all in your repo, in the same directory, is flow.

Architecture

Imdone CLI gives you:

your-repo/
β”œβ”€β”€ src/               # Your code
β”‚   └── auth.js
β”œβ”€β”€ tests/             # Your tests
β”‚   └── auth.test.js
└── backlog/           # Your issues (WITH attachments)
    └── current-sprint/
        └── PROJ-123/
            β”œβ”€β”€ issue-PROJ-123.md         # Issue content
            β”œβ”€β”€ comments-PROJ-123.md      # Discussion
            └── attachments/              # Files
                β”œβ”€β”€ error-log.txt
                β”œβ”€β”€ screenshot.png
                └── architecture.png
Enter fullscreen mode Exit fullscreen mode

Everything in one place. Edit anything. Push to sync.

Try It

npm install -g imdone-cli@0.39.0
imdone init
imdone pull
Enter fullscreen mode Exit fullscreen mode

Two-way sync for Jira issues, comments, and attachments.
All as Markdown and files in your repo.
All in your editor.

Because your best work happens in your editor, not your browser.


Links:


What's your biggest Jira workflow pain point? Drop it in the comments. πŸ‘‡

Top comments (0)