Skip to content

Redmine

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.

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

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.

CategoryKeys
Statusstatus_new, status_in_progress, status_resolved, status_feedback, status_closed, status_rejected
Prioritypriority_low, priority_normal, priority_high, priority_urgent, priority_immediate
Trackertracker_bug, tracker_feature, tracker_task, tracker_support
Activityactivity_design, activity_development, activity_testing, activity_documentation, activity_support, activity_management, activity_devops, activity_review

23 tools across seven areas. Deletes are permanent and cannot be undone.

ToolWhat it does
listIssueIdsLists issue IDs with filters for project, status, assignee, tracker, and priority.
getIssueFullGets complete issue data, including custom fields, journals, attachments, and relations.
searchIssueIdsSearches issues by text query, optionally scoped to a project.
createIssueCreates a new issue, with tracker, status, priority, assignee, and parent by ID or name.
updateIssueUpdates an existing issue’s fields and adds a note in the same call.
commentIssueAdds a comment (journal entry) to an issue.
listJournalsLists journal entries (comments and history) for an issue.
updateJournalEdits the notes on an existing journal entry.
deleteJournal (destructive)Permanently removes a journal entry.
listTimeEntriesLists logged time with filters for issue, project, user, and date range.
createTimeEntryLogs time against an issue or project.
updateTimeEntryUpdates hours, activity, or comments on an existing time entry.
listUsersLists users, optionally filtered to a project’s members.
resolveUserResolves me, a user ID, or a username to a user ID.
getCurrentUserReturns the authenticated user’s profile.
listProjectIdsLists project IDs with a status filter.
getProjectFullGets complete project data, including trackers, categories, and modules.
searchProjectIdsSearches projects by name, identifier, or description.
listRelationsLists an issue’s relations to other issues.
createRelationLinks two issues with a relation type and, for precedes or follows, a delay in days.
deleteRelation (destructive)Permanently removes a relation.
getMappingsReturns the project’s ID mappings for status, priority, tracker, and activity.
getConfigReturns the active project ID, name, and URL.

Relation types: relates, duplicates, duplicated, blocks, blocked, precedes, follows, copied_to, copied_from.

  1. In Redmine, open My account and copy the API access key.
  2. Open the Redmine integration card in the Desktop app and start the wizard. Enter your Redmine URL and API Key, then click Validate.
  3. Once validated, pick a project (or All projects) and confirm the ID mappings for status, priority, tracker, and activity.
  4. Save. Restart the project’s containers if prompted so the worker picks up the configuration.

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.