New: watch your coding agents work, step by step, on a live board. Try the demo, no account

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

What each call does
CallEffect on the board
POST /api/tasksA new task, marked as added by an agent
PATCH /api/tasks/{id} with status in_progressThe card moves to Working now with the job's name and a start time
POST /api/tasks/{id}/subtasks with stepsThe bar splits into one segment per stage
PATCH a step with status doneThat segment fills; the bar advances by one stage
PATCH the task with status blocked and blocked_reasonThe 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