HydraIssue is an issue reporting microservice for the Hydra ecosystem. It provides a public web form for reporting issues, an API for programmatic access, and an admin dashboard for triage and management.
curl https://issues.experiencenet.com/api/v1/health
| Method | Path | Auth | Description | |--------|------|------|-------------| | GET /api/v1/health | none | Health check | | GET /uploads/{id}/{filename} | none | Serve uploaded attachment | | POST /api/v1/issues | Bearer (api) | Create issue | | GET /api/v1/issues | Bearer (api) | List issues (query: status, category, project, active_only) | | GET /api/v1/issues/{id} | Bearer (api) | Get single issue | | PATCH /api/v1/issues/{id} | Bearer (api) | Update issue (status, priority, category, plan, custom_fields) | | DELETE /api/v1/issues/{id} | Bearer (api) | Delete issue | | PUT /api/v1/issues/{id}/plan | Bearer (api) | Update plan text and status | | POST /api/v1/issues/{id}/comments | Bearer (api) | Add comment | | POST /api/v1/issues/{id}/nim-actions | Bearer (api) | Record agent action (name, action) | | GET /api/v1/stats | Bearer (api) | Aggregate statistics | | GET /api/v1/reports/quality | Bearer (api) | Quality review report (query: since, until, format) | | POST /api/v1/webhooks | Bearer (api) | Register a webhook | | GET /api/v1/webhooks | Bearer (api) | List registered webhooks | | DELETE /api/v1/webhooks/{id} | Bearer (api) | Unregister a webhook | | GET /api/v1/runbook | none | This runbook (markdown) |
Session cookie auth (/login with the admin token), not Bearer.
| Method | Path | Description |
|--------|------|-------------|
| GET /admin | Dashboard |
| GET /admin/issues | Issue list |
| GET /admin/issues/{id} | Issue detail |
| POST /admin/issues/{id}/status | Update status |
| POST /admin/issues/{id}/priority | Update priority |
| POST /admin/issues/{id}/comment | Add comment |
| POST /admin/issues/{id}/attachments | Upload attachments (multipart, field attachments) |
A single field tracking the full issue lifecycle from creation through implementation.
| Status | Meaning | Set by |
|--------|---------|--------|
| open | New issue, not yet groomed | Issue creation |
| groomed | Triaged and ready for planning | groom-issues skill |
| planning | Agent is writing an implementation plan | plan-issues skill |
| proposed | Plan submitted for human review | plan-issues skill |
| accepted | Plan approved, ready for implementation | Human via UI |
| rejected | Plan rejected, parked until a human moves it back to groomed | Human via UI |
| implementing | Agent is actively implementing the plan | next-plan skill |
| done | Implementation is complete | next-plan skill |
| closed | Issue closed manually (won't fix, duplicate, etc.) | Human via UI |
Transition rules: Terminal states (done, closed) cannot regress to earlier lifecycle states. For example, a done issue cannot be set back to groomed or open. Terminal states can only transition to each other (done ↔ closed). The API returns 409 Conflict when an invalid transition is attempted.
The status filter supports comma-separated values: ?status=open,groomed,planning
The stage query parameter provides semantic shortcuts for common agent queries. It resolves server-side to the appropriate status values, so skills don't need to hardcode statuses.
| Stage | Resolves to | Used by |
|-------|------------|---------|
| groomable | open | groom-issues |
| plannable | groomed | plan-issues |
| implementable | accepted | next-plan |
| active | all except done, closed | dashboards |
Example: GET /api/v1/issues?stage=plannable
| Priority | Meaning |
|----------|---------|
| (unset) | Not yet triaged |
| low | Nice to have, no urgency |
| medium | Should be addressed in normal course |
| high | Needs attention soon |
| critical | Blocking or production-impacting |
| Category | Meaning |
|----------|---------|
| bug | Something is broken |
| feature | New functionality request |
| improvement | Enhancement to existing functionality |
| question | Clarification or support request |
| unclassified | Default when no category specified |
Issues support an optional custom_fields JSON object for project-specific metadata. Custom fields are stored as a free-form key-value map — no schema is enforced.
curl -X POST -H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{"title":"Example","description":"...","project":"nimsforest","custom_fields":{"environment":"staging","severity_score":8}}' \
https://issues.experiencenet.com/api/v1/issues
Custom fields can also be set or replaced via PATCH /api/v1/issues/{id} with the custom_fields key.
The public report form (/report) includes an optional "Custom fields" section where users can enter a JSON object.
Custom fields render as key-value pairs on both the public issue view and the admin detail page.
Files live on disk under ~/.hydraissue/data/uploads/{issue_id}/, and the issue YAML holds the
stored filenames. Stored names are prefixed with an index (0_notes.txt, 1_spec.md), so the same
filename uploaded twice is kept twice rather than overwritten.
| Where | Who | Notes |
|-------|-----|-------|
| /report | anyone | Optional attachments on the public report form |
| POST /admin/issues/{id}/attachments | admin session | Upload form on the admin issue detail page; appends to the existing list |
Limits apply to both paths: 50 MB per file, and executable extensions (.exe, .dll, .bat,
.cmd, .ps1, .vbs, .msi, .dmg, .app, .scr, .com) are rejected. Rejected or oversized
files are skipped silently, and the rest of the upload still succeeds.
An admin upload updates the issue's updated_at and fires the issue.updated webhook.
There is no delete. To remove an attachment, delete the file under uploads/{issue_id}/ and edit
the attachments list in the issue YAML.
/report) or the API (POST /api/v1/issues)~/.hydraissue/data/issues/~/.hydraissue/data/issues.yaml enables fast listing/admin) using session cookie authPUT /api/v1/issues/{id}/plan — the status lifecycle (proposed → accepted → implementing → done) provides human-in-the-loop approval before agents executeExternal services can register webhooks to receive issue events in real time. Registrations are dynamic — no config changes or restarts needed.
curl -X POST -H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{"url":"https://example.com/webhooks/issues","events":["issue.created","issue.updated"],"projects":["nimsforest2"]}' \
https://issues.experiencenet.com/api/v1/webhooks
issue.created, issue.updated, issue.commentedcurl -H "Authorization: Bearer $TOKEN" https://issues.experiencenet.com/api/v1/webhooks
curl -X DELETE -H "Authorization: Bearer $TOKEN" \
https://issues.experiencenet.com/api/v1/webhooks/wh_1
{
"event": "issue.created",
"timestamp": "2026-03-04T12:00:00Z",
"data": { ... full issue object ... }
}
Delivery is fire-and-forget with 3 retries (1s, 2s backoff) and a 5s timeout per attempt.
Agent actions are tracked via append-only nim_actions on each issue. This prevents duplicate processing and provides an audit trail.
curl -X POST -H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{"name":"nebula","action":"groomed"}' \
https://issues.experiencenet.com/api/v1/issues/42/nim-actions
Common actions: groomed, planning, planned, implementing, implemented.
Users can attach files (images, PDFs, logs, archives, etc.) when submitting issues via the web form.
/root/.hydraissue/data/uploads/{issue_id}/{i}_{filename}GET /uploads/{id}/{filename} (public, no auth required).exe, .dll, .bat, .cmd, .ps1, .vbs, .msi, .dmg, .app, .scr, .com[a-zA-Z0-9\-_.] only; path traversal is rejectedTo clean up orphaned upload directories:
ls /root/.hydraissue/data/uploads/
# Remove dirs for deleted issues manually if needed
Two separate tokens configured in config.yaml:
HydraIssue auto-updates from releases.experiencenet.com every 6 hours via hydrarelease. Disabled in dev mode (--dev).
To check the current version:
hydraissue version
cat /root/.hydraissue/config.yamlss -tlnp | grep 8085journalctl -u hydraissue -f?active_only=true to filter, default shows all for backward compatibility.ls /root/.hydraissue/data/issues/cat /root/.hydraissue/data/issues.yamlapi_token in configHetzner automated daily server snapshots are enabled on hydrastreamingmonitor (78.47.174.83), context hydraexperiencenet. Backup window: 02:00–06:00 UTC, 7-day retention.
The snapshot covers the entire server disk, including:
/root/.hydraissue/data/issues/ — all issue YAML files/root/.hydraissue/data/uploads/ — file attachments/root/.hydraissue/data/issues.yaml — index/root/.hydraissue/config.yaml — service confighydraexperiencenet project), open Servers → hydrastreamingmonitor → Backups.curl https://issues.experiencenet.com/api/v1/health
curl -H "Authorization: Bearer $TOKEN" https://issues.experiencenet.com/api/v1/issues?active_only=true
If only the data directory needs to be recovered (e.g. accidental deletion), mount the snapshot as a temporary volume or copy files off it via the Hetzner rescue system, then rsync back to /root/.hydraissue/data/.