Pipa time tracking
Operational skills for the agents people already use.
npx -y skills add lunchpaillola/pipa-skills --skill pipa-time-trackingAssembled from the repository path, not quoted from the project. Check it against their README if it does not work.
One thing to look at
- 1 stars1 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.
What its author says it does
Copied from the file, not written here
Track work time through Pipa generic agent utility records. Use when user asks to start, stop, switch, inspect, backfill, update, archive, or summarize time entries.
SKILL.md
12.4 KB, as published. Nobody here has run it
Pipa Time Tracking
User time-tracking req -> Pipa creds -> generic time_tracking/time_entry utility records.
CRITICAL: Use only Toggl-style time entries via generic Pipa 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
-
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 -> review.
- Update/delete/cancel/archive entry -> update/archive.
- Buy credits/top up, check credit balance, or mutating req fails with
insufficient_credits-> top-up. - Payroll, invoicing, 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.
-
Load creds. Required before API calls:
PIPA_API_BASE_URLPIPA_API_KEYPIPA_EMAILPIPA_USER_TIMEZONE
Aliases:
PIPA_FOLLOW_UP_API_KEY->PIPA_API_KEYPIPA_FOLLOW_UP_EMAIL->PIPA_EMAIL- If canonical and alias values both exist in the same source, canonical wins.
Lookup order:
- Gateway-injected values.
- Env vars.
- Repo-local
.pipa/credentials. - User-global
~/.pipa/credentials.
Hidden-path rule:
- Do not trust glob/file-search for
.pipa/credentials; hidden dirs can be skipped/mishandled. - Check explicit paths directly:
<workspace-root>/.pipa/credentials, then~/.pipa/credentials. - Shell helper: resolve root from cwd or
git rev-parse --show-toplevel; readPath(root) / ".pipa" / "credentials". No files foundfrom glob for.pipa/credentialsis inconclusive. Direct-read before asking user for creds.
Creds file = dotenv, not JSON:
PIPA_API_BASE_URL=https://pailflow-chat-gateway.fly.dev PIPA_API_KEY=<API_KEY> PIPA_EMAIL=<EMAIL> PIPA_USER_TIMEZONE=<IANA_TIMEZONE>Legacy shape:
PIPA_API_BASE_URL=https://pailflow-chat-gateway.fly.dev PIPA_FOLLOW_UP_API_KEY=<API_KEY> PIPA_FOLLOW_UP_EMAIL=<EMAIL> PIPA_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
PIPA_API_BASE_URLand API key exist, continue to selected mode. If mode needs local-day interpretation and timezone missing, step 3. -
Set up missing creds only when needed. Fill smallest missing piece.
- Missing
PIPA_USER_TIMEZONE+ local dates/vague times -> ask exactly:What timezone should I use?Stop. - Missing
PIPA_API_BASE_URL-> defaulthttps://pailflow-chat-gateway.fly.devunless user named another gateway. - Missing
PIPA_API_KEYandPIPA_FOLLOW_UP_API_KEY-> ask for user's email.
Email-code setup:
- Explain email-code verification creates/replaces Pipa agent utilities key. Mention key replacement revokes prior keys only if user may already have one.
POST /v1/key/email-code/startwith productagent-utilities.- Ask for one-time email code.
POST /v1/key/email-code/verifywith challenge id, code, productagent-utilities.- Store returned key unless env ephemeral, user opted out, or write fails.
- Prefer repo-local
.pipa/credentialsfor repo-local skills;~/.pipa/credentialsfor global skills. - Before repo-local write, ensure
.pipa/gitignored. Use file mode600. - Tell user storage path. Never print key unless explicitly asked.
- Reload creds, continue selected mode.
- Missing
-
API contract. Use only:
GET /v1/agent-utility-recordsPOST /v1/agent-utility-recordsGET /v1/agent-utility-records/:idPATCH /v1/agent-utility-records/:idDELETE /v1/agent-utility-records/:idPOST /v1/key/email-code/startPOST /v1/key/email-code/verifyPOST /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_creditsincludestopup_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_typerecord_typestatusstarted_at_gtestarted_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 ${PIPA_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" } }Rules:
runningrequiresstarted_at, omitsended_at.completedrequiresstarted_atandended_at.ended_atmust be >=started_at.- Only one unarchived running
time_tracking/time_entryper user. - Deletes archive. Do not claim hard-delete.
- Store exact timestamps. Round duration only in user-facing response.
-
Start mode.
- Title from req. If only "start timer", use
Untitled work. - Parse obvious labels only: project, client, task/tag/phase. Do not invent labels.
GET /v1/agent-utility-records?utility_type=time_tracking&record_type=time_entry&status=running.- If running timer exists, report id/title/start. Ask exactly:
Do you want me to switch from that timer to [new title]?Stop. - If none running, create
runningrecord with current UTC ISOstarted_at. - Fresh
Idempotency-Keyfor create. - 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" } - Title from req. If only "start timer", use
-
Switch mode.
- Fetch running timer per step 5.
- If none, create new running timer via start mode. Mention no prior timer stopped.
- If running, patch to
status=completed,ended_at=now. - After stop succeeds, create new running timer with a fresh
Idempotency-Key. - If stop succeeds but create fails, say exactly that and report no new timer running.
- Return stopped duration + new running record id.
-
Stop mode.
- Fetch running timer per step 5.
- If none, say no timer currently running, stop.
- Patch running record:
status=completed,ended_at=now. - Confirm id, title, start, end, duration, labels.
Patch payload:
{ "status": "completed", "ended_at": "2026-06-30T14:15:00.000Z" } -
Current mode.
- Fetch running timer per step 5.
- If none, say no timer currently running.
- If one, report id, title, start, elapsed duration, labels.
- Do not create/stop/mutate.
-
Backfill mode.
- Resolve date/time range with
PIPA_USER_TIMEZONE. - Ambiguous date/time/duration/timezone -> ask one direct clarification, stop.
- Convert
started_at/ended_atto UTC ISO. - Create
completedrecord. - Return created entry confirmation.
If user says "log 45 minutes from 9:00" and timezone/date known, compute end immediately. No extra confirmation.
- Resolve date/time range with
-
Review mode.
- Resolve range to concrete
started_at_gteandstarted_at_ltUTC ISO. For "today", usePIPA_USER_TIMEZONE. GET /v1/agent-utility-recordswithutility_type=time_tracking,record_type=time_entry, range filters.- Exclude archived unless user asks archived/cancelled.
- Group/total records in response. Do not call/invent reporting endpoint.
- Include running entries separately; duration changes.
- Resolve range to concrete
-
Update/archive mode.
- Resolve record id from req, context, or short candidate list.
- Ambiguous ref -> ask one direct question, stop.
PATCH /v1/agent-utility-records/:idfor title, timestamps, labels, rate, metadata.DELETE /v1/agent-utility-records/:idonly for explicit delete/cancel/remove/archive.- Archiving running timer -> say cancelled/archived, not completed.
-
Top-up mode.
Time Tracking costs 10 Pipa 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.
- Use on
insufficient_creditsor buy/top-up ask. - Choose requested integer credit amount.
- No amount -> ask exactly:
How many Pipa credits do you want to buy?Stop. POST /v1/topups/checkout-sessionswith{ "credits": amount }.- Share
checkout_urlas Markdown link, e.g.[Open checkout](...), plus amount. - If checkout unavailable and API only includes
billing_url, share billing fallback. - After payment confirmation, retry original mutating req.
If
insufficient_creditsorinvalid_topup_creditsreturns 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? - The skill cannot query current credit balance unless an allowed response includes
-
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 sharebilling_urlunless 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.
-
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.