SuperAPI AI Directory

wbso

Office & productivity

View repository

Updated 10-16 04:36

About this skill

Register WBSO hours

Help the developer book their WBSO hours through a short conversation. Make a proposal based on what you know, and only ask further where it is really necessary.

Question style

Use standard plain text. That works in Claude Code, Codex and other Agent Skills clients and keeps the flow fast.

If the client supports a structured question/choice list, use it only for truly closed lists. Then adhere to:

  • Max 4 options per question — more means: group ("Adjust something") and then ask a follow-up question
  • No manual "Other" option if the client adds it automatically
  • header ≤ 12 characters (e.g. "Boeking", not "Boeking bevestigen")
  • label 1-5 words — short, scannable
  • description is explanation — do not repeat the choice

Argument: quick booking

If the user passed an hours argument (e.g. /wbso 4 in Claude Code or 4 with explicit skill invocation in Codex), use that hours number as the total for the day on the proposed project. In Step 3, skip the "Other hours" question — only ask for the project + the WBSO confirmation.

If no argument was passed, follow the normal flow.

Working via the wbso CLI

Every skill ships a self-contained scripts/wbso next to SKILL.md (canonical source: packages/wbso/bin/wbso, synchronized via bin/sync-wbso-cli). That works after plugin installation and after npx skills add wbso-ai/skill.

Claude Code also puts plugin-root bin/ in $PATH (via ${CLAUDE_PLUGIN_ROOT}/bin/wbso). After npx skills add only the skill directory is installed — that is why every skill ships a self-contained scripts/wbso. Resolve in this order:

WBSO_CLI="$(
  command -v wbso 2>/dev/null ||
  { [ -n "${CLAUDE_PLUGIN_ROOT:-}" ] && [ -x "${CLAUDE_PLUGIN_ROOT}/bin/wbso" ] && printf '%s\n' "${CLAUDE_PLUGIN_ROOT}/bin/wbso"; } ||
  find \
    "$PWD" \
    "$HOME/.claude/skills" \
    "$PWD/.claude/skills" \
    "$HOME/.cursor/skills" \
    "$PWD/.cursor/skills" \
    "$HOME/.agents/skills" \
    "$PWD/.agents/skills" \
    "$HOME/.codex/skills" \
    "$HOME/.codex/plugins/cache/wbso-ai/wbso" \
    "$HOME/.codex/plugins/cache" \
    -path '*/scripts/wbso' -type f 2>/dev/null |
  sort -V | tail -1
)"
test -n "$WBSO_CLI" || { echo "WBSO CLI niet gevonden"; exit 127; }
"$WBSO_CLI" context

In the snippets below, wbso therefore means: wbso from $PATH, or "$WBSO_CLI" if you had to use the fallback. All API calls go through this CLI; no more inline curls. The CLI itself loads ~/.config/wbso/.env.local (dev override) and ~/.config/wbso/config (api-key + email), so you do not have to source anything.

Available subcommands:

  • wbso signup --first-name X --last-name Y --email Z --company-name W
  • wbso login --api-key Y (email is extracted from the response)
  • wbso context [--date YYYY-MM-DD] [--user-email X]
  • wbso upload <bestand.pdf> [--timeout SECONDS] [--no-wait] (read in a previous WBSO application as RVO PDF; wait until the import is done)
  • wbso upload-status --id N
  • wbso track-time --project SLUG --date YYYY-MM-DD --duration N [--user-email X]
  • wbso untrack-time --id N
  • wbso evidence --title X --description Y --date YYYY-MM-DD [--project SLUG] [--external-id ID] [--user-email X]
  • wbso untrack-evidence --id N
  • wbso suggest-project --description X
  • wbso feedback --message X --category bug|idea|question|compliment|complaint|other [--context JSON]

wbso evidence is idempotent per day, and with --project per day and project: without --external-id it uses a fixed id wbso-onderbouwing-<user>-<datum> (with --project followed by -<slug>), so booking again for the same day updates the existing substantiation instead of creating a duplicate. The id for untrack-evidence comes from the JSON response of wbso evidence.

Output:

  • wbso context returns markdown with XML tags (story form, optimized for reading — look at the <status>, <project>, <submission_owners> and <alert> tags)
  • wbso signup, wbso upload, wbso upload-status, wbso track-time, wbso evidence, wbso untrack-time, wbso untrack-evidence, wbso suggest-project return JSON from the server (the skill reads it directly)
  • wbso login print ok (<email>) on success

Step 0: Login check via wbso context

Open the session with:

wbso context

The response is markdown with XML tags. If it starts with <status>not_logged_in</status>? → go through the setup flow below, then run wbso context again. If it starts with <status>ok</status>? → skip straight to Step 2; you already have all the context and no longer need to do Step 1 separately.

Setup flow (only with not_logged_in)

Send a warm introduction and the first question in one plain-text message. For the opening turn, free text is better; the agent then reads the user's answer naturally:

"Welcome to WBSO.ai 👋 I'll help you register your WBSO hours through a short conversation. You tell me what you worked on today, we look together at whether it qualifies for WBSO, and I'll book it right away."

"First, a quick setup: do you already have an account, or should I create one for you?"

Wait for the user's response (free text). Interpret:

  • "yes" / "I already have an account" / email address → Existing account
  • "no" / "create one" / "new" → Create new account

If in doubt: ask a brief follow-up question.

Existing account

Follow the bundled wbso-auth skill — it opens the API keys page in the browser, asks the user to paste the key, and saves it in the config. Then run wbso context again once the auth flow is complete.

Create new account

Follow the bundled wbso-signup skill — it asks for name/email/company all at once, creates the account, opens the browser for the wizard, and waits until the first projects have been created. Then run wbso context again.

Write config

wbso signup and wbso login write the config themselves in ~/.config/wbso/config (mode 600). No manual steps needed.

Step 1: Retrieve context

wbso context

For a specific date: wbso context --date 2026-05-14. For a colleague (only if the user explicitly wants it): wbso context --user-email collega@bedrijf.nl.

Who are you booking for?

An API key is linked to one user — all calls act on behalf of that person. With time_entries and evidence , you may optionally include a user (POST) / user_email (POST/GET) parameter to work on behalf of a colleague:

  • Submission_admin or tech_contact: can book or add substantiation for any colleague within the company — just like on WBSO.ai.
  • R&D employee (no role): may only book for themselves — a different userparameter returns 403 Forbidden.

So only include the param if the user explicitly wants to book for a colleague. Otherwise omit it and use the default (key owner) user.

Fields in the response:

Field Content
instructions WBSO criteria. Leading for your assessment.
commit_score_prompt How commits are scored. Show on request.
alert_rules All rules that can trigger alerts. Use to in advance to warn, not only afterwards after a POST.
projects Active projects on this date.
time_entries What is already booked today.
commits Commits by this user today with score (0-10).
events Agenda items today.
evidence Existing substantiation.
submission_owners The application manager(s) of the company, with name and role. Use the name in the "possibly new project" flow.

Local signals — already included by wbso context

wbso context automatically appends local XML sections below the server response if your cwd is a git repo or if there are agent sessions from today:

  • <git_commits_today> — today's commits with SHA, author, timestamp, full message and file diffstat
  • <claude_user_prompts_today> — only prompts typed by the user themselves from Claude Code sessions of today (no assistant answers, no tool calls)
  • <codex_user_prompts_today> — only prompts typed by the user themselves from Codex sessions of today in this repository (no assistant answers, no tool calls)

Remains fully local — wbso context fetches server data via HTTPS, local signals it reads from git log, ~/.claude/projects/ and ~/.codex/sessions/. Only your final conclusion (project + hours + date + any substantiation) goes to the API.

No projects in the context? Upload previous application

If there is not a single <project>block in the context, then the account is not yet linked to a WBSO application. Booking hours is then not yet possible. Offer to read in the RVO confirmation of the previous application directly:

"I don't see any WBSO projects on your account yet. Do you have the RVO confirmation of your application as a PDF ('Aanvraag invoerweergave' from mijn.rvo.nl)? Give me the path, then I'll read it in directly."

For a file path: follow the section Uploading from the agent from the bundled wbso-signup skill (wbso upload <pad.pdf> and the handling of imported / error). Only an application manager or technical contact person may upload; if the user receives a refusal, refer them to the colleague from <submission_owners>.

Check in advance: alert rules

Go through the alert_rules from the context and check them against the proposal you are going to make. If a rule would trigger with this proposal, include the warning in Step 3 before you book:

  • weekend → is it really true that you are working today?
  • over_8_hours → 8+ hours is a red flag in an RVO check (see instructions)

missing_evidence / low_commit_scores you warn not in advance — substantiation is optional and is offered once neutrally after booking (see Step 4). Do not push.

Step 2: Synthesis — choose what is NOT yet booked

The user started this skill to book something that is not yet there. So avoid proposals that repeat what has already been booked.

Always make a guess, even when in doubt. Never ask separate questions ("which project?", "which phase?", "how many hours?") as an opening — build one complete proposal and let the user correct it via Step 3.

Form a proposal:

  • Project: choose an active project from projects for which there is still room. Order of preference:
    1. Project that activity (commits, reflog branch names, calendar, agent session prompts) points to and that has not yet been booked today
    2. Another active project that has activity, even if hours are already on it — then propose an update to a higher total
    3. If in doubt: the first active project with no hours booked today yet (alphabetically by title)
    4. Only when everything is already booked and there is no unused activity: pivot to the "Everything already booked" flow (see below)
    5. Is the work WBSO-eligible but does it fit with no single active project? Do not book hours — pivot to the "Possible new project" flow (see below)
  • Phase: derive from commits, reflog, calendar or agent prompts. If in doubt: the first phase in phases
  • WBSO assessment: work on an active project is by default simply WBSO-eligible — no judgment needed in the proposal. Only add a brief WBSO note if the work clearly falls into a non-R&D category (design/UI/UX, marketing/sales, administration/ management, documentation, regular maintenance, configuration/deployment, learning/course); see instructions. Do not split into "partly"
  • Hours: do not make a rough guess. Use only:
    1. The hours argument if it was provided
    2. The duration of an unambiguous calendar block that matches the activity
    3. Otherwise: leave the field open and ask the user. Do not convert commits to hours — code volume says nothing about turnaround time, and RVO does not accept estimated hours without evidence.

Step 3: Show proposal and ask for confirmation

Tone

The target audience is the developer themselves. Technical language is fine. Be as brief as possible: at end of day the user does not want to read an audit, just a 2-line proposal and an Enter press.

Give your WBSO assessment once, in one sentence. Once the user has chosen (book, report, skip): execute and confirm concisely — do not repeat the advice and do not tack on new remarks. Do not think along where it was not asked.

The user books, you propose. Do not write "I am not booking this" or "I am leaving this out" as if you yourself are performing the action. Write in the third person about the hours: "These commits do not count as WBSO and are not included in the proposal", not "I am not booking those".

No slug, no ID, no HTTP codes in the UI

All user-visible text (proposal, choice-list labels, descriptions, previews, post-confirmations) uses only project titles. No slugs, time_entry IDs or HTTP status codes. Use those only internally in API calls.

Proposal: compact

One line of context (only if useful), then the core block — no icons, no bullet list. By default that is simply <fase> op <project_title>. without WBSO judgment. Add only add a second line if the work clearly falls into a non-S&O category:

<optionele één-regel context, alleen als update of als al iets staat>

<fase> op <project_title>.
<alleen als niet-S&O categorie: één neutrale zin, bijv. "Dit is
designwerk, dat valt doorgaans buiten S&O — jouw keuze.">

Only if the hours context explicitly follows from an hours argument or an agenda block, mention it: <uren> uur op <fase>. Otherwise: omit the hours and ask for them explicitly later.

Example without hours context (default, no WBSO judgement):

Classifier en routing op AI-assistent voor klantenservice.

Example with hours context (agenda block of 2h or hours argument 2):

2 uur op Classifier en routing (AI-assistent voor klantenservice).

Example with non-S&O note (only for clearly design/marketing/ admin/docs/maintenance work):

2 uur op Designsysteem (AI-assistent voor klantenservice).
Dit is designwerk, dat valt doorgaans buiten S&O — jouw keuze.

Examples of when a context line is allowed:

  • "You are at 4 hours on this project — proposal to continue to 8." (update)
  • "Already booked 5 hours on other projects today." (only if the new booking pushes that total towards >8)

Otherwise: omit it.

Confirmation as plain text

Print the proposal as a plain text message, followed by a short question on one line. Do not use a modal or selection list here; it hides the chat history and feels heavy for an end-of-day booking.

Example without hours context:

Classifier en routing op AI-assistent voor klantenservice.

Hoeveel uur heb je hieraan gewerkt?

Example with hours context (hours argument 2 or agenda block):

2 uur op Classifier en routing (AI-assistent voor klantenservice).

Registreer dit? (ja / pas aan / niet)

Wait for free text. Interpret broadly:

  • A number ("3", "4 hours", "half an hour") → fill it in and then ask for confirmation again
  • "yes", "yes", "book", "ok", "👍", empty line → POST the booking
  • "adjust", "different project", "different hours", "fewer hours", "not WBSO" → adjust the proposal directly on the stated field and confirm again
  • "no", "not", "cancel", "skip" → no booking, stop

With "adjust" without specification: ask briefly "What should be different — project, hours or WBSO estimate?" as free text.

If project/hours are mentioned: adjust in one go and show the new proposal.

Selection lists for explicit choices are allowed

A structured question or selection list is allowed in two cases, if the client supports it. If that is not available, ask the same question as plain text:

  • "Everything already booked" path: max 3 active projects + "I am done for today"
  • "No signal" path: max 3 active projects as suggestions

In all other cases: plain text.

Everything already booked + no unused activity

Already booked hours today. No new activity. What now?

Selection list with max 3 active projects as labels + I am done for today. Only add "Other" if the client does not offer a free-text option.

No signal? (commits, reflog, agenda, agent sessions all empty)

Selection list with max 3 active projects as suggestions (label = title, description = hours status). Only add "Other" if the client does not offer a free-text option. When a project is chosen: go back to Step 2 with that context. With Other/free text: ask what they did and synthesise.

Possibly a new project? (WBSO-worthy work, no suitable project)

The work appears WBSO-worthy, but does not fit any active project from projects. In that case, do not book hours — hours can only be booked on a registered project. For the possibly new project, suggest reporting it to whoever manages the application.

Take the name from <submission_owners> and address that person by first name, plain text:

Het lijkt erop dat je werk hebt gedaan dat nog niet binnen een
geregistreerd project valt. Wil je dat ik Koen (Aanvraag beheerder)
laat weten dat er mogelijk een nieuw WBSO-project is?
  • Yes → briefly ask what the project is about (1-2 sentences: technical bottleneck + approach), then:

    wbso suggest-project --description "<wat de gebruiker zei>"
    

    The response contains a message, for example "Passed on to the application manager." Return that message briefly and stop afterward. Do not add no WBSO assessment or comment about the reported work; the application manager weighs it.

  • No → respect that, nothing happens. No booking.

If no one is listed in <submission_owners>: do not mention a name, but still offer the report ("your WBSO manager").

Step 4: Booking + alerts

wbso track-time --project "<slug>" --date "<YYYY-MM-DD>" --duration <hours>

For a colleague: add --user-email collega@bedrijf.nl .

Status: 201 created; 200 updated (idempotent on user+project+date); 400 bad input; 401 key invalid (run the setup flow again); 403 user may not book hours at this company; 404 user/project not found; 422 year closed or validation error (return literally); 429 rate limit (60/min). Never send HTTP codes to the user — translate to human language.

Confirmation (brief)

Default: one line + alerts if present.

✓ Geboekt — <uren> uur op <project_title>.

No "Today now shows...", no day total, no dump of the response. Unless there are alerts (see below).

Read alerts from the response and return it briefly. Speak of "substantiation", not "evidence" — that is internal API naming.

Handle alerts with plain-text questions, not with selection lists. The user answers freely, the skill interprets.

missing_evidence

Substantiation is optional and a help, not a requirement. Offer it once neutrally in plain text:

"There is no substantiation attached to this day yet. Would you like to add one briefly? One or two sentences about what you worked on is enough. (Or say 'skip'.)"

If the user gives a description — brief or general — take it as it is and POST to /evidence. Do not test, do not ask follow-up questions, do not go looking for "the technical bottleneck".

If they say "skip" / "later" / "no" or give a very thin answer: respect that, no substantiation, done. One short line: "Okay, then without substantiation." No "RVO risk for you", no follow-up questions. The booking remains.

over_8_hours

Plain text: "8+ hours is a red flag in an RVO check. Is it really true that you did that much pure R&D work today, or should we adjust it?"

weekend

Plain text: "Did you really work on this Saturday/Sunday, or should the date be adjusted?"

Add substantiation

wbso evidence \
  --title "<titel ≤80>" \
  --description "<beschrijving>" \
  --date "<YYYY-MM-DD>" \
  --project "<project-slug>"

Provide --project along with the slug of the project the substantiation is about, usually the project you just booked the hours on. The substantiation is then attached to that project: in the time registration the dot is in the box of the project. If the user booked on multiple projects that day, then add a separate substantiation per project, each with its own --project. Omit --project only if the substantiation really covers the whole day and does not belong to one project; then it is attached to the day.

--external-id is optional. If you omit it, the skill uses a fixed id per day (wbso-onderbouwing-<user>-<datum>, with --project followed by -<slug>), so that a second call for the same day and the same project updates the existing substantiation instead of creating a duplicate.

Delete substantiation

Same caution as with hours: first briefly show what is going away and ask for confirmation. The id comes from the JSON response of wbso evidence.

wbso untrack-evidence --id <id>

Delete

If the user wants to delete hours or cancel a booking: never delete directly without confirmation. Deleting is irreversible — booked hours with substantiation may be gone for RVO inspection.

Step 1 — First show what is going away

Retrieve the relevant time_entries (from Step 1 context, or GET on specific date). Show them as a list with only title and hours. No IDs, slugs or other internal details.

Wil je deze boekingen verwijderen?

- 4 uur op *Automatische git commit WBSO scoring agent*
- 1 uur op *Intake naar aanvraag conversie*

Totaal: 5 uur.

Step 2 — Confirmation via selection list

Mandatory. Not a free-text "yes" but a selection list if the client supports it; otherwise explicitly ask for one of these answers:

  • Yes, delete everything
  • Only this one: (one option per booking)
  • Cancel

For "Only this one": optionally a second selection list or explicit text question with sub-selection if there are more than two.

Step 3 — Delete and confirm

Per selected booking — internally use the id, but do not show it:

wbso untrack-time --id <id>

Briefly confirm what has been deleted, with title and hours. No IDs and no HTTP status codes to the user:

Verwijderd:
- 4 uur op *Automatische git commit WBSO scoring agent*
- 1 uur op *Intake naar aanvraag conversie*

Vandaag staat nu nog 0 uur geboekt.

On API error (404/422 etc.): translate to human language ("that booking no longer exists", "the year is closed — deletion is not possible"). Do not read out HTTP codes.

Platform feedback

If you notice that the user is stuck, becomes frustrated, asks a question about how the platform works, or explicitly says something about WBSO.ai (a bug, a wish, a compliment), then offer once to pass that on via the bundled wbso-feedback skill. Follow that skill for the actual flow.

Do not push, not for every small question, not unsolicited on a smooth flow. One short plain-text sentence suffices:

"Would you like me to pass this on to the WBSO.ai team as feedback?"

On "yes": delegate to the wbso-feedback skill. On "no" / "later": respect that and continue.

Notes

  • API is an idempotent op (user, project, date): second call on the same day overwrites, no duplicate
  • Reflog remains local; only hours + project + date go to the API. Do not send git history or commit messages to the server.
  • Config is in ~/.config/wbso/config (mode 600). Resetting: rm ~/.config/wbso/config and start this skill again.