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

  • An Administrator-created full-access Keito integration key, bound to the human or Agent identity used by the workflow and stored as KEITO_API_KEY in GitHub Secrets. Personal read-only sync keys cannot create time entries.
  • 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

Mode Trigger Result
labels Closed issues and merged pull requests Logs labels such as time: 1h30m.
commands Issue and pull request comments Logs slash commands such as /time 45m Fixed OAuth.
activity PR merges, reviews, and pushes Creates draft metadata entries from GitHub activity.
auto All supported events Commands 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

Input Required Default Description
api-key Yes Keito API key.
account-id No Company ID. Can also come from account_id or workspace_id in config.
project-id No Default project ID.
task-id No Default task ID.
mode No auto labels, commands, activity, or auto.
config-path No .keito/config.yml Repo config path.
label-prefix No time: Prefix for time labels.
command-prefixes No /time,/t,/log,/keito Command prefixes.
default-day-hours No 8 Hours represented by 1d.
confirm-in-comments No true Post comments or reactions in GitHub.
draft No false Add metadata.draft for labels and commands.
api-base-url No https://app.keito.ai API base URL override.
github-token No ${{ github.token }} Token used for GitHub comments and reactions.
dry-run No false Build entries without calling Keito.
fail-on-error No false Fail the workflow step instead of warning.
debug No false Enable 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

Symptom Fix
Authentication failed Check KEITO_API_KEY and KEITO_ACCOUNT_ID.
No project or task resolved Set project-id and task-id, or add them to .keito/config.yml.
No entry created Check the workflow event and selected mode.
Duplicate skipped The action found an existing entry with the same metadata.dedupe_key.
No GitHub comment Add issues: write and pull-requests: write, or set confirm-in-comments: false.