GitHub Action

The Keito GitHub Action creates billable time entries from repository activity. Use it when work should be logged from GitHub issues, pull requests, comments, reviews, or commits instead of from a manually started CI timer.

Use the Keito CLI when a CI job needs an explicit start/stop timer around a script. Use the GitHub Action when repository events are the source of truth.

Prerequisites

  • A Keito API key stored as KEITO_API_KEY in GitHub Secrets.
  • A Keito Company ID from Settings > API & Developers > Company ID.
  • A Keito project ID and task ID, or a repository .keito/config.yml.
  • The GitHub Action repository: osodevops/keito-action.

The action writes to Keito API v2:

POST https://app.keito.ai/api/v2/time_entries
Authorization: Bearer <api-key>
Keito-Account-Id: <company_id>

Quick Start

Add .github/workflows/keito.yml:

name: Keito Time Tracking

on:
  issues:
    types: [closed]
  pull_request:
    types: [closed]
  issue_comment:
    types: [created]

permissions:
  contents: read
  issues: write
  pull-requests: write

jobs:
  log-time:
    runs-on: ubuntu-latest
    steps:
      - uses: osodevops/keito-action@0aec31cb257e6d64e5f45a8491c4db06463b0ca4
        with:
          api-key: ${{ secrets.KEITO_API_KEY }}
          account-id: ${{ secrets.KEITO_ACCOUNT_ID }}
          project-id: ${{ vars.KEITO_PROJECT_ID }}
          task-id: ${{ vars.KEITO_TASK_ID }}
          mode: auto

The pinned SHA above points at the v1.0.0 release. For simpler Marketplace installs, you can use osodevops/keito-action@v1 after the v1 tag is available in your organization policy.

Modes

ModeTriggerResult
labelsClosed issues and merged pull requestsLogs labels such as time: 1h30m.
commandsIssue and pull request commentsLogs slash commands such as /time 45m Fixed OAuth.
activityPR merges, reviews, and pushesCreates draft metadata entries from GitHub activity.
autoAll supported eventsCommands win, then labels, then activity.

Labels Mode

Use labels such as time: 15m, time: 1h, time: 1h30m, or time: 1d.

on:
  issues:
    types: [closed]
  pull_request:
    types: [closed]

permissions:
  contents: read
  issues: write
  pull-requests: write

jobs:
  log:
    runs-on: ubuntu-latest
    steps:
      - uses: osodevops/keito-action@0aec31cb257e6d64e5f45a8491c4db06463b0ca4
        with:
          api-key: ${{ secrets.KEITO_API_KEY }}
          account-id: ${{ secrets.KEITO_ACCOUNT_ID }}
          project-id: ${{ vars.KEITO_PROJECT_ID }}
          task-id: ${{ vars.KEITO_TASK_ID }}
          mode: labels

When an issue closes or a pull request is merged, the action creates a completed time entry and adds GitHub context to metadata.

Commands Mode

Use slash comments on issues and pull requests:

/time 45m Fixed OAuth callback handling
/t 1h30m prj_acme tsk_dev Review and tests

Supported command prefixes are /time, /t, /log, and /keito by default. Project and task overrides are optional and must be Keito IDs.

on:
  issue_comment:
    types: [created]
  pull_request_review_comment:
    types: [created]

permissions:
  contents: read
  issues: write
  pull-requests: write

jobs:
  log:
    runs-on: ubuntu-latest
    steps:
      - uses: osodevops/keito-action@0aec31cb257e6d64e5f45a8491c4db06463b0ca4
        with:
          api-key: ${{ secrets.KEITO_API_KEY }}
          account-id: ${{ secrets.KEITO_ACCOUNT_ID }}
          project-id: ${{ vars.KEITO_PROJECT_ID }}
          task-id: ${{ vars.KEITO_TASK_ID }}
          mode: commands

The action reacts to the comment on success. On failure it adds a failure reaction and posts a short error reply when comment permissions are available.

Activity Mode

Activity mode creates draft metadata entries from pull request merges, review submissions, and pushes to non-default branches.

on:
  pull_request:
    types: [closed]
  pull_request_review:
    types: [submitted]
  push:
    branches-ignore:
      - main

permissions:
  contents: read
  issues: write
  pull-requests: write

jobs:
  log:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5
      - uses: osodevops/keito-action@0aec31cb257e6d64e5f45a8491c4db06463b0ca4
        with:
          api-key: ${{ secrets.KEITO_API_KEY }}
          account-id: ${{ secrets.KEITO_ACCOUNT_ID }}
          mode: activity
          config-path: .keito/config.yml

Activity mode always sets metadata.draft: true. Review generated entries before billing clients.

Repository Config

The action reads the same top-level .keito/config.yml fields used by the Keito Agent Skill:

version: 1
workspace_id: co_example
account_id: co_example
client_id: cli_example
client_name: "Example Client"
project_id: prj_example
project_name: "Example Project"
task_id: tsk_development
task_name: "Development"
metadata:
  cost_centre: engineering

The action also supports optional rules for monorepos:

rules:
  - match:
      branch: "client/acme/*"
    project_id: prj_acme
    task_id: tsk_frontend
  - match:
      paths: ["apps/billing/**"]
    project_id: prj_billing

Resolution order is command override, matching config rule, explicit workflow input, then config default.

Agent-Aware Commits

Activity mode can mark commits as source=agent when a configured commit trailer matches:

agents:
  commit_trailers:
    - name: "Co-Authored-By"
      value_regex: "claude|gpt|agent"
      source: agent
      metadata:
        agent_type: claude-code

This keeps GitHub Action entries aligned with entries created by the Keito Agent Skill, while still tagging the integration as github_action.

Inputs

InputRequiredDefaultDescription
api-keyYesKeito API key.
account-idNoCompany ID. Can also come from account_id or workspace_id in config.
project-idNoDefault project ID.
task-idNoDefault task ID.
modeNoautolabels, commands, activity, or auto.
config-pathNo.keito/config.ymlRepo config path.
label-prefixNotime:Prefix for time labels.
command-prefixesNo/time,/t,/log,/keitoCommand prefixes.
default-day-hoursNo8Hours represented by 1d.
confirm-in-commentsNotruePost comments or reactions in GitHub.
draftNofalseAdd metadata.draft for labels and commands.
api-base-urlNohttps://app.keito.aiAPI base URL override.
github-tokenNo${{ github.token }}Token used for GitHub comments and reactions.
dry-runNofalseBuild entries without calling Keito.
fail-on-errorNofalseFail the workflow step instead of warning.
debugNofalseEnable verbose action debug logs.

Metadata

Entries created by the action include:

{
  "integration": "github_action",
  "mode": "labels",
  "repo": "acme/app",
  "html_url": "https://github.com/acme/app/issues/42",
  "event": "issues.closed",
  "dedupe_key": "acme%2Fapp/issue/42/issues.closed/time%3A%201h"
}

Metadata is capped at 4KB. The action trims long contextual fields before creating the time entry.

Troubleshooting

SymptomFix
Authentication failedCheck KEITO_API_KEY and KEITO_ACCOUNT_ID.
No project or task resolvedSet project-id and task-id, or add them to .keito/config.yml.
No entry createdCheck the workflow event and selected mode.
Duplicate skippedThe action found an existing entry with the same metadata.dedupe_key.
No GitHub commentAdd issues: write and pull-requests: write, or set confirm-in-comments: false.