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_KEYin 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
| 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. |