keelapps/Satchel for Jira/Documentation
Documentation
Satchel does two things: it gets attachments out of Jira in bulk, and it tells you what is in there. Everything below is one of those two, plus the parts where Jira's own limits decide what is possible.
Jira's issue view does not show app panels automatically. On an issue, open the View app actions button under the issue title — the round icon, not the “+” — and choose Attachments. The panel then stays visible on that issue.
This is the single most common “is the app broken?” moment after installing, and it is Jira's behaviour rather than the app's.
Finding the panel
Satchel has three surfaces:
- The issue panel — View app actions → Attachments on any issue. Lists the issue's attachments and downloads them, individually or as one zip.
- The project page — Project → Satchel. Browse, JQL, the inventory, duplicates and storage reports for that project.
- The admin page — Apps → Satchel, for site administrators: settings, the deletion switch and the audit trail.
A panel stuck permanently on “Loading Satchel…” is a bug worth reporting, not slowness: every call the interface makes is timed out and turns into a visible error.
Downloading one issue
From the issue panel:
- Download all as zip — every attachment on the issue in one archive, however many there are, including well past the 150 at which Jira's own attachment rendering gives up.
- Download one file — direct, skipping Jira's preview step entirely.
Two things the archive guarantees:
-
Duplicate filenames are renamed, never overwritten. Three files
called
screenshot.pngarrive as three files. - Anything missing is named. If a file could not be included, a note inside the zip says which one and why. The archive never quietly comes up short.
A long download shows progress and can be cancelled.
A JQL result, or a project
The project page's browser lists the project's issues and their attachments, filterable
and searchable, with JQL for anything more specific. Select rows — or take the whole
result — and download one archive foldered by ISSUE-KEY/, so the files
arrive already sorted by the issue they belong to.
The scan behind a project-wide result runs as a background job with a checkpoint, so a large project finishes rather than timing out, and closing the tab does not lose the work.
How the bytes travel
This is the part worth being precise about, because the app's compliance story rests on it.
The archive is assembled in your browser tab. The compression library is part of the app's own bundle rather than fetched from a content delivery network — a CDN would need an external network permission, and that permission is exactly what the app does not have. Bytes go Jira → your tab → your disk. Nothing is written to app storage, and nothing reaches any server we operate, because we operate none.
There are two routes for getting those bytes into the tab, and which one runs is measured rather than assumed:
| Route | How | Trade-off |
|---|---|---|
| Bridge | the browser calls Jira directly, as you | fastest, and no backend function runs at all — but the platform bridge can mangle non-text payloads on some sites |
| Relay | the backend reads the file in slices and hands them to the tab | correct for every file type, slower, and subject to a per-file ceiling |
On the first download Satchel probes which route returns bytes intact on your site, then uses it and says on screen which one is in use and why. Both routes are zero-egress; the relay is slower, not less private.
The project inventory
A scan records, for every attachment in the project: filename, byte size, media type, upload date, uploader, and the issue and issue type it belongs to. Metadata only — never file content. That inventory is what the duplicate and storage reports are computed from, and what the CSV export writes out.
The ten most recent scans per project are kept; creating an eleventh deletes the oldest. You can delete a scan yourself from the project page.
The scan itself runs as the app rather than as you, because a queued background job has no signed-in user. Its output is metadata for a governance report — and anything you then ask to download is re-fetched as you, so Jira's permissions still decide what you can actually have.
Duplicate candidates
Satchel groups files by filename and exact byte size and reports the bytes each group would reclaim if all but one copy went away.
They are called candidates on purpose. Jira exposes no content hash for an attachment, so proving two files byte-identical would mean downloading both — across a project, every byte in it. What Satchel can honestly say is “same name, same size”, and that qualification travels with the number in the data itself, so no screen can render a reclaimable figure without the sentence that limits it.
Two deliberate exclusions follow from the same honesty:
- Same name, different size is not grouped. That is usually two revisions of a document, and deleting one of them loses work.
- Same size, different name is not grouped. At small sizes that is a coincidence, and a common one.
Storage reports
Jira gives you one site-wide storage figure. Satchel breaks the project's share of it down by:
- Uploader — who put it there.
- File type — the screenshots-versus-videos question.
- Issue type — where in the workflow the weight accumulates.
- Age — how much of it predates anyone who still works here.
- The biggest files — the short list that usually accounts for most of it.
CSV export
The whole inventory exports as CSV: one row per attachment with its metadata. Useful when the person who has to approve a deletion is not the person running the app.
Bulk deletion
Jira has no recycle bin for attachments. An attachment deleted through Satchel is gone from Jira, and the only recovery is an Atlassian support restore of the entire site. Satchel cannot undo a deletion, and does not pretend it can.
So deletion is fenced in four ways:
- It ships switched off. A site administrator has to enable it.
- It is administrator-only even once enabled.
- It requires a dry run — the exact files, the exact count, the exact bytes — and then a typed confirmation.
- Every deleted file leaves an audit record: who, what, when, and the reason they typed.
Audit records are capped at 500 per project, oldest dropped first, and they are deliberately not deletable from the interface — an audit trail a user can erase is not an audit trail. To clear one, contact support.
Download what you are deleting first. That is what the zip is for.
What runs as you
Every attachment read and every deletion runs as you, using your own Atlassian identity. If you cannot open a file in Jira, Satchel cannot hand it to you — including attachments hidden by issue security levels or added inside restricted comments, which Jira withholds at the API level.
The one exception is the background project scan described above, which runs as the app because a queued job has no signed-in user.
Permissions the app requests
| Scope | Why |
|---|---|
read:jira-work | read issues, run JQL, read attachment metadata and attachment content — how the app finds and downloads files |
read:jira-user | turn an uploader's account id into a display name, so a storage report names people |
write:jira-work | one API call only: deleting an attachment |
storage:app | scan records, audit records and settings, in Atlassian-hosted storage on your own site |
write:jira-work is broader than what Satchel does with it, and that
deserves stating plainly. Atlassian's consent text for it mentions creating and editing
issues, posting comments, creating worklogs and deleting issues. Satchel does
none of those things. It is the narrowest scope Atlassian currently offers
that includes deleting an attachment — the granular scope that would say exactly that
is still in Beta — and a test in the build fails if any code path reaches a mutating
call other than the single attachment delete. That test exists to stop the gap between
the consent prompt and the behaviour from widening silently.
There is no permissions.external block: the app cannot make an outbound
call even if it tried to, which Atlassian enforces at the platform level.
Licensing and the free tier
Sites with 10 users or fewer pay nothing. Above that, two things stay free forever on every install: the single-issue zip and the direct single-file download. The fix for the seven-year-old missing download button is never behind a licence check.
A licence buys scale and governance: cross-issue and project-wide archives, the project inventory, the duplicate and storage reports, CSV export, and deletion.
Not in this release
- Uploading attachments. No write scope for it, and no path to it in the interface.
- Cross-project inventories. The project page is scoped to its own project; a site-wide inventory is a different permissions conversation.
- Scheduled inventories. One more trigger and a daily invocation to usually find nothing. Run one on demand instead.
- Content-hash duplicate detection. Not possible without downloading every byte; see duplicate candidates.
- Confluence attachments — those are Satchel for Confluence.
Support
Questions, bug reports and feature requests: raise a support request. Security issues: report privately.