Redmine
What it does
Section titled “What it does”The Redmine integration lets Speedwave read and update issues, time entries, journals, and users in your Redmine instance. It supports self-hosted and on-premise instances, including private addresses and Tailscale CGNAT ranges. Setting a project during setup scopes Speedwave’s work to it, so it fits naturally into planning and turning requirements into user stories.
What it consists of
Section titled “What it consists of”Speedwave runs Redmine as a worker container and routes Claude’s tool calls to it. The worker mounts a read-only file at /tokens/api_key holding the API key, and reads a config.json in the same folder for the Redmine URL, an optional project ID and name, and the ID mappings for status, priority, tracker, and activity. Both files live under ~/.speedwave/tokens/<project>/redmine/.
Directory~/.speedwave/tokens/<project>/redmine/
- api_key
- config.json
How it works
Section titled “How it works”You connect Redmine with an API key, not OAuth or a username and password. The Desktop app’s configuration wizard validates the key, then fetches your projects, statuses, trackers, priorities, and activities so you can confirm the ID mappings. It auto-matches names by dropping each key’s category prefix and comparing the rest to Redmine’s names case-insensitively; a non-English instance won’t auto-match, so those need picking by hand.
Mappings link friendly keys such as status_new or priority_high to a project’s numeric Redmine IDs, since the same name can point to a different ID on each instance. You can add custom keys too; the config file accepts any category_name pair. Speedwave reads mappings with getMappings before creating or updating an issue, and getConfig returns the active project ID, name, and URL. An unmapped friendly name fails with an error listing the available values for that field.
Issue descriptions, notes, journals, and comments are Textile markup, not Markdown, and Speedwave sanitizes them before sending, stripping dangerous HTML tags and script-like URI schemes while keeping a safe set of formatting tags.
Setting project_id scopes more than the tool list: reads are forced to that project, mutations are checked against it first, and moving an issue elsewhere with updateIssue is blocked with a scope error. Missing host_url in config.json falls back to a REDMINE_URL environment variable.
API errors return plain guidance: 401 for a bad key, 403 for insufficient permission, 404 for a missing item, 422 for Redmine’s own field validation errors, and a network-error message when the request never lands. Failed requests retry automatically up to 3 times, waiting 2, 4, then 8 seconds.
ID mapping keys
Section titled “ID mapping keys”| Category | Keys |
|---|---|
| Status | status_new, status_in_progress, status_resolved, status_feedback, status_closed, status_rejected |
| Priority | priority_low, priority_normal, priority_high, priority_urgent, priority_immediate |
| Tracker | tracker_bug, tracker_feature, tracker_task, tracker_support |
| Activity | activity_design, activity_development, activity_testing, activity_documentation, activity_support, activity_management, activity_devops, activity_review |
What Speedwave can do
Section titled “What Speedwave can do”23 tools across seven areas. Deletes are permanent and cannot be undone.
| Tool | What it does |
|---|---|
listIssueIds | Lists issue IDs with filters for project, status, assignee, tracker, and priority. |
getIssueFull | Gets complete issue data, including custom fields, journals, attachments, and relations. |
searchIssueIds | Searches issues by text query, optionally scoped to a project. |
createIssue | Creates a new issue, with tracker, status, priority, assignee, and parent by ID or name. |
updateIssue | Updates an existing issue’s fields and adds a note in the same call. |
commentIssue | Adds a comment (journal entry) to an issue. |
listJournals | Lists journal entries (comments and history) for an issue. |
updateJournal | Edits the notes on an existing journal entry. |
deleteJournal (destructive) | Permanently removes a journal entry. |
listTimeEntries | Lists logged time with filters for issue, project, user, and date range. |
createTimeEntry | Logs time against an issue or project. |
updateTimeEntry | Updates hours, activity, or comments on an existing time entry. |
listUsers | Lists users, optionally filtered to a project’s members. |
resolveUser | Resolves me, a user ID, or a username to a user ID. |
getCurrentUser | Returns the authenticated user’s profile. |
listProjectIds | Lists project IDs with a status filter. |
getProjectFull | Gets complete project data, including trackers, categories, and modules. |
searchProjectIds | Searches projects by name, identifier, or description. |
listRelations | Lists an issue’s relations to other issues. |
createRelation | Links two issues with a relation type and, for precedes or follows, a delay in days. |
deleteRelation (destructive) | Permanently removes a relation. |
getMappings | Returns the project’s ID mappings for status, priority, tracker, and activity. |
getConfig | Returns the active project ID, name, and URL. |
Relation types: relates, duplicates, duplicated, blocks, blocked, precedes, follows, copied_to, copied_from.
Set it up
Section titled “Set it up”- In Redmine, open My account and copy the API access key.
- Open the Redmine integration card in the Desktop app and start the wizard. Enter your Redmine URL and API Key, then click Validate.
- Once validated, pick a project (or All projects) and confirm the ID mappings for status, priority, tracker, and activity.
- Save. Restart the project’s containers if prompted so the worker picks up the configuration.
Security boundaries
Section titled “Security boundaries”The Redmine worker mounts only its own API key, read-only, with no access to other services’ tokens or credentials. See how credentials are handled for how Speedwave isolates each worker’s secrets. When project_id is unset, Speedwave can pass one per call instead of being locked to one project.