Docs / Recipes / How-to
Report CI and deploy progress to Taskhold
Anything that can make an HTTP request can report into Taskhold, not only coding agents. A deploy job that shows up on the live board next to your agents means one place to look. This recipe uses the REST API from GitHub Actions; the same calls work from any CI system or a cron job.
Before you begin
- Create an API key in Taskhold Settings and name it after the job, for example "CI deploy".
- Add it to the repository as the secret TASKHOLD_API_KEY.
- The X-Taskhold-Agent header sets the name shown on the board, here "GitHub Actions (deploy)".
The workflow
# .github/workflows/deploy.yml (excerpt): one Taskhold task per run, one step per stage.
jobs:
deploy:
runs-on: ubuntu-latest
env:
TH: https://taskhold.com/api
AUTH: "Authorization: Bearer ${{ secrets.TASKHOLD_API_KEY }}"
AGENT: "X-Taskhold-Agent: GitHub Actions (${{ github.workflow }})"
steps:
- uses: actions/checkout@v4
- name: Open a Taskhold task with steps
id: th
run: |
json() { curl -sf -H "$AUTH" -H "$AGENT" -H "Content-Type: application/json" "$@"; }
task=$(json "$TH/tasks" -d "{\"title\": \"Deploy ${GITHUB_SHA::7}\", \"priority\": \"high\"}" | jq -r .task.id)
json -X PATCH "$TH/tasks/$task" -d '{"status": "in_progress"}' > /dev/null
read -r build test ship < <(json "$TH/tasks/$task/subtasks" \
-d '{"steps": ["Build", "Test", "Ship"]}' | jq -r '[.subtasks[].id] | join(" ")')
echo "task=$task" >> "$GITHUB_OUTPUT"
echo "build=$build" >> "$GITHUB_OUTPUT"
echo "test=$test" >> "$GITHUB_OUTPUT"
echo "ship=$ship" >> "$GITHUB_OUTPUT"
- name: Build
run: |
curl -sf -X PATCH "$TH/tasks/${{ steps.th.outputs.build }}" -H "$AUTH" -H "$AGENT" \
-H "Content-Type: application/json" -d '{"status": "in_progress"}' > /dev/null
make build
curl -sf -X PATCH "$TH/tasks/${{ steps.th.outputs.build }}" -H "$AUTH" -H "$AGENT" \
-H "Content-Type: application/json" -d '{"status": "done"}' > /dev/null
# ... the same for Test and Ship ...
- name: Tell the person if it failed
if: failure()
run: |
url="$GITHUB_SERVER_URL/$GITHUB_REPOSITORY/actions/runs/$GITHUB_RUN_ID"
curl -sf -X PATCH "$TH/tasks/${{ steps.th.outputs.task }}" -H "$AUTH" -H "$AGENT" \
-H "Content-Type: application/json" \
-d "{\"status\": \"blocked\", \"blocked_reason\": \"Deploy failed. Logs: $url\"}"What each call does
| Call | Effect on the board |
|---|---|
| POST /api/tasks | A new task, marked as added by an agent |
| PATCH /api/tasks/{id} with status in_progress | The card moves to Working now with the job's name and a start time |
| POST /api/tasks/{id}/subtasks with steps | The bar splits into one segment per stage |
| PATCH a step with status done | That segment fills; the bar advances by one stage |
| PATCH the task with status blocked and blocked_reason | The card moves to Needs you with the logs link |
For a long stage, report counts inside it with POST /api/tasks/{step_id}/progress and a body like {"current": 120, "total": 400, "message": "Uploading assets"}.
Read next
Updated 2026-10-26 · Markdown for agents · Questions: hello@greatwork.company