360 Secure SkillHub
360 安全技能中心

opskeep-time-tracking

通过 Opskeep 通用代理工具记录接口管理时间跟踪:按用户请求开始、停止、切换、回填、更新或归档 time_entry 记录;查看运行中计时器并汇总指定区间的工作时长、可计费与未开票时长,以及按客户和币种分组的金额;额度不足时可走充值流程。

CalebPrince
热度 0.00
最近更新 2026-10-18 16:48:28
分类:自动化依赖:代码执行 / 读写文件 / 第三方 API应用场景:任务管理 / 工作流 / 报告撰写

安装技能

复制下面的话术发给你的 Agent,它会通过 secure-skills 检索并安装该技能。

执行命令安装此 skill: npx secure-skills-cli add calebprince/opskeep-skills/opskeep-time-tracking
Metadata
name
opskeep-time-tracking
description
Track work time through Opskeep generic agent utility records. Use when user asks to start, stop, switch, inspect, backfill, update, archive, or summarize time entries, including billable vs non-billable time, the value of unbilled time per client before invoicing, and marking entries as billed on an invoice.
metadata
{"lane":"meta","version":"0.2.0"}

Opskeep Time Tracking

User time-tracking req -> Opskeep creds -> generic time_tracking/time_entry utility records.

CRITICAL: Use only Toggl-style time entries via generic Opskeep agent utility records API. Do not use Clockify, Toggl, screenshots, payroll, invoicing, productivity scoring, passive activity reconstruction, or /v1/time-tracking/* wrapper endpoints.

Keep short todo list: mode, creds, missing question, payload validation, API call, final response.

Workflow

  1. Pick mode. Choose exactly one.

    • Start timer: "start tracking this", "start timer for Acme", "track time on frontend fixes" -> start.
    • Switch work: "switch to Acme QA" -> switch.
    • Stop current timer -> stop.
    • Ask what is running -> current.
    • Log past time: "log 45 minutes from 9 to 9:45" -> backfill.
    • Show entries / summarize time / "what unbilled time do I have for Acme?" -> review.
    • "Those hours went on INV-0142" -> update/archive (mark billed).
    • Update/delete/cancel/archive entry -> update/archive.
    • Buy credits/top up, check credit balance, or mutating req fails with insufficient_credits -> top-up.
    • Payroll, creating/sending invoices (that's opskeep-get-paid), screenshots, passive reconstruction, external tracker sync, recurring timers, auto idle detection -> explain V1 unsupported, stop.

    If conversation already has successful API response and user asks about that result, answer from known response. Do not call unsupported reporting endpoints.

  2. Load creds. Required before API calls:

    • OPSKEEP_API_BASE_URL
    • OPSKEEP_API_KEY
    • OPSKEEP_EMAIL
    • OPSKEEP_USER_TIMEZONE

    Aliases:

    • OPSKEEP_FOLLOW_UP_API_KEY -> OPSKEEP_API_KEY
    • OPSKEEP_FOLLOW_UP_EMAIL -> OPSKEEP_EMAIL
    • If canonical and alias values both exist in the same source, canonical wins.

    Lookup order:

    1. Gateway-injected values.
    2. Env vars.
    3. Repo-local .opskeep/credentials.
    4. User-global ~/.opskeep/credentials.

    Hidden-path rule:

    • Do not trust glob/file-search for .opskeep/credentials; hidden dirs can be skipped/mishandled.
    • Check explicit paths directly: <workspace-root>/.opskeep/credentials, then ~/.opskeep/credentials.
    • Shell helper: resolve root from cwd or git rev-parse --show-toplevel; read Path(root) / ".opskeep" / "credentials".
    • No files found from glob for .opskeep/credentials is inconclusive. Direct-read before asking user for creds.

    Creds file = dotenv, not JSON:

    OPSKEEP_API_BASE_URL=https://pailflow-chat-gateway.fly.dev
    OPSKEEP_API_KEY=<API_KEY>
    OPSKEEP_EMAIL=<EMAIL>
    OPSKEEP_USER_TIMEZONE=<IANA_TIMEZONE>
    

    Legacy shape:

    OPSKEEP_API_BASE_URL=https://pailflow-chat-gateway.fly.dev
    OPSKEEP_FOLLOW_UP_API_KEY=<API_KEY>
    OPSKEEP_FOLLOW_UP_EMAIL=<EMAIL>
    OPSKEEP_USER_TIMEZONE=<IANA_TIMEZONE>
    

    Keep API keys out of chat/logs/markdown/shell history/process args when possible. Shell helper reads creds inside script; prints only non-secret results.

    If OPSKEEP_API_BASE_URL and API key exist, continue to selected mode. If mode needs local-day interpretation and timezone missing, step 3.

  3. Set up missing creds only when needed. Fill smallest missing piece.

    • Missing OPSKEEP_USER_TIMEZONE + local dates/vague times -> ask exactly: What timezone should I use? Stop.
    • Missing OPSKEEP_API_BASE_URL -> default https://pailflow-chat-gateway.fly.dev unless user named another gateway.
    • Missing OPSKEEP_API_KEY and OPSKEEP_FOLLOW_UP_API_KEY -> ask for user's email.

    Email-code setup:

    1. Explain email-code verification creates/replaces Opskeep agent utilities key. Mention key replacement revokes prior keys only if user may already have one.
    2. POST /v1/key/email-code/start with product agent-utilities.
    3. Ask for one-time email code.
    4. POST /v1/key/email-code/verify with challenge id, code, product agent-utilities.
    5. Store returned key unless env ephemeral, user opted out, or write fails.
    6. Prefer repo-local .opskeep/credentials for repo-local skills; ~/.opskeep/credentials for global skills.
    7. Before repo-local write, ensure .opskeep/ gitignored. Use file mode 600.
    8. Tell user storage path. Never print key unless explicitly asked.
    9. Reload creds, continue selected mode.
  4. API contract. Use only:

    • GET /v1/agent-utility-records
    • POST /v1/agent-utility-records
    • GET /v1/agent-utility-records/:id
    • PATCH /v1/agent-utility-records/:id
    • DELETE /v1/agent-utility-records/:id
    • POST /v1/key/email-code/start
    • POST /v1/key/email-code/verify
    • POST /v1/topups/checkout-sessions

    Credit balance:

    • Do not invent a balance endpoint. Current credit balance is only known when an allowed API response includes credits_remaining.
    • If the user asks for balance and the latest allowed response lacks credits_remaining, say the skill cannot query current balance directly.
    • If insufficient_credits includes topup_limits, use those limits in the next action.
    • Treat checkout URLs as user-action payment links. Do not persist them or raw-print long checkout URLs unless explicitly asked.

    List query params used by this skill:

    • utility_type
    • record_type
    • status
    • started_at_gte
    • started_at_lt

    Do not use other list filters unless the API response or docs expose them. If archived filtering is unavailable, exclude archived records after fetch.

    Auth header:

    Authorization: Bearer ${OPSKEEP_API_KEY}
    

    Time entry record:

    {
      "utility_type": "time_tracking",
      "record_type": "time_entry",
      "status": "running",
      "title": "Work description",
      "started_at": "2026-06-30T13:00:00.000Z",
      "project_label": "optional project",
      "client_label": "optional client",
      "flex_label": "optional tag/task/phase",
      "rate_amount": 150,
      "rate_currency": "USD",
      "metadata": { "notes": "optional extras", "billable": true, "invoice_ref": null }
    }
    

    Billing fields (inside metadata, so no extra endpoint is needed):

    • billable: true unless the user says the time is non-billable (admin, internal, unpaid rework). Entries without the field count as billable.
    • invoice_ref: set to the invoice number once the time is billed; null or absent means unbilled.
    • Set rate_amount/rate_currency only from the user's stated rate. Never assume one.

    Rules:

    • running requires started_at, omits ended_at.
    • completed requires started_at and ended_at.
    • ended_at must be >= started_at.
    • Only one unarchived running time_tracking/time_entry per user.
    • Deletes archive. Do not claim hard-delete.
    • Store exact timestamps. Round duration only in user-facing response.
  5. Start mode.

    1. Title from req. If only "start timer", use Untitled work.
    2. Parse obvious labels only: project, client, task/tag/phase. Do not invent labels.
    3. GET /v1/agent-utility-records?utility_type=time_tracking&record_type=time_entry&status=running.
    4. If running timer exists, report id/title/start. Ask exactly: Do you want me to switch from that timer to [new title]? Stop.
    5. If none running, create running record with current UTC ISO started_at.
    6. Fresh Idempotency-Key for create.
    7. Success -> step 14 start template.

    Create payload:

    {
      "utility_type": "time_tracking",
      "record_type": "time_entry",
      "status": "running",
      "title": "Acme frontend fixes",
      "started_at": "2026-06-30T13:00:00.000Z",
      "project_label": "Acme",
      "client_label": "Acme Co",
      "flex_label": "frontend"
    }
    
  6. Switch mode.

    1. Fetch running timer per step 5.
    2. If none, create new running timer via start mode. Mention no prior timer stopped.
    3. If running, patch to status=completed, ended_at=now.
    4. After stop succeeds, create new running timer with a fresh Idempotency-Key.
    5. If stop succeeds but create fails, say exactly that and report no new timer running.
    6. Return stopped duration + new running record id.
  7. Stop mode.

    1. Fetch running timer per step 5.
    2. If none, say no timer currently running, stop.
    3. Patch running record: status=completed, ended_at=now.
    4. Confirm id, title, start, end, duration, labels.

    Patch payload:

    { "status": "completed", "ended_at": "2026-06-30T14:15:00.000Z" }
    
  8. Current mode.

    1. Fetch running timer per step 5.
    2. If none, say no timer currently running.
    3. If one, report id, title, start, elapsed duration, labels.
    4. Do not create/stop/mutate.
  9. Backfill mode.

    1. Resolve date/time range with OPSKEEP_USER_TIMEZONE.
    2. Ambiguous date/time/duration/timezone -> ask one direct clarification, stop.
    3. Convert started_at/ended_at to UTC ISO.
    4. Create completed record.
    5. Return created entry confirmation.

    If user says "log 45 minutes from 9:00" and timezone/date known, compute end immediately. No extra confirmation.

  10. Review mode.

    1. Resolve range to concrete started_at_gte and started_at_lt UTC ISO. For "today", use OPSKEEP_USER_TIMEZONE.
    2. GET /v1/agent-utility-records with utility_type=time_tracking, record_type=time_entry, range filters.
    3. Exclude archived unless user asks archived/cancelled.
    4. Group/total records in response. Do not call/invent reporting endpoint.
    5. Include running entries separately; duration changes.
    6. Billing views (computed from fetched records, no extra endpoint):
      • Unbilled: billable entries with no metadata.invoice_ref.
      • Value: hours x rate_amount, grouped by client_label and per rate_currency. Never add different currencies. Entries without a rate show hours with value TBD.
      • Non-billable: hours only, listed separately. Hand the unbilled value to opskeep-get-paid for invoicing; this skill doesn't create invoices.
  11. Update/archive mode.

    1. Resolve record id from req, context, or short candidate list.
    2. Ambiguous ref -> ask one direct question, stop.
    3. PATCH /v1/agent-utility-records/:id for title, timestamps, labels, rate, metadata. Mark billed: patch each entry's metadata with invoice_ref (merge with existing metadata, don't drop notes). Confirm the entry list and invoice number first.
    4. DELETE /v1/agent-utility-records/:id only for explicit delete/cancel/remove/archive.
    5. Archiving running timer -> say cancelled/archived, not completed.
  12. Top-up mode.

    Time Tracking costs 10 Opskeep credits for 30 days. No auto-renewal; next mutating use after expiry charges another access pass.

    Balance visibility:

    • The skill cannot query current credit balance unless an allowed response includes credits_remaining.
    • If the user asks how many credits they have and no current response includes credits_remaining, say so and include the gateway URL being used.
    1. Use on insufficient_credits or buy/top-up ask.
    2. Choose requested integer credit amount.
    3. No amount -> ask exactly: How many Opskeep credits do you want to buy? Stop.
    4. POST /v1/topups/checkout-sessions with { "credits": amount }.
    5. Share checkout_url as Markdown link, e.g. [Open checkout](...), plus amount.
    6. If checkout unavailable and API only includes billing_url, share billing fallback.
    7. After payment confirmation, retry original mutating req.

    If insufficient_credits or invalid_topup_credits returns limits, use them. Example: 10 credits is below the minimum. Smallest top-up is 100 credits for $10. Want me to create that checkout session?

  13. API failures. Do smallest next action.

    • running_timer_exists: Fetch running timer, explain, ask whether to switch.
    • insufficient_credits: Step 12.
    • invalid_api_key: Explain replacement key rotates account key, step 3.
    • started_at_required, completed_entry_requires_ended_at, running_entry_cannot_have_ended_at, ended_at_before_started_at: Fix payload; ask only if requested time ambiguous.
    • agent_utility_record_not_found: Ask for record id, or list recent candidates if user asked about "that entry".
    • invalid_topup_credits: Give smallest valid next action from API response. Example: 10 credits is below the minimum. Smallest top-up is 100 credits for $10. Want me to create that checkout session? Do not share billing_url unless checkout unavailable.
    • failed_to_create_agent_utility_record, failed_to_patch_agent_utility_record, failed_to_archive_agent_utility_record: State whether anything changed before failure. Do not pretend timer changed.
    • Missing API key: Step 3.

    Do not restart full workflow unless error requires it.

  14. Report. Crisp, operational, auditable.

    Start template:

    Started the timer.
    
    - Record ID: `[id]`
    - Title: `[title]`
    - Started: `[started_at]`
    - Labels: `[project/client/flex or none]`
    

    Stop template:

    Stopped the timer.
    
    - Record ID: `[id]`
    - Title: `[title]`
    - Time: `[started_at]` to `[ended_at]`
    - Duration: `[rounded duration]`
    - Labels: `[project/client/flex or none]`
    

    Rules:

    • Ask only missing/ambiguous required info.
    • Ask exactly one direct follow-up question at a time.
    • Do not dump API metadata.
    • Do not store secrets in skill file.
    • Mention credits remaining when API returns it.
    • Failures: state whether any record changed before failure.