agentleFS
FloriferousFloriferous/tipee-tools/.claude/skills/tipee/SKILL.md

tipee

Skill1 starsChanged 15 days agoMITView on GitHub

Working on tipee-tools (Effect 4 core client, MCP server, Claude Code plugin, MSW test kit) — tipee access rights, API quirks vs. its docs, guardrails. Use whenever a task touches tipee, shifts, absences, or this repository's packages.

  • Reads credentials

The file

We split this skill into the rules it gives an agent

3 rules. About 0 are common, 0 are distinctive, and 3 are very specific to this project.

  • ≈0

    Common · estimate

    Many files like this have a rule of this kind.

  • ≈0

    Distinctive · estimate

    This author's own choices. Worth a look.

  • 3

    Very specific

    Tied to their project's names, files or tools. Probably skip.

  • Common
  • Distinctive
  • Very specific
  1. Very specific:

    The API key is a secret: only in packages/mcp/.env or the Claude app's own settings, never in chat, commits or CI.

    line 40
  2. Very specific:

    Run pnpm spec:refresh locally (without --bump) to do the same by hand.

    line 153
  3. Very specific:

    No build step: Node 24 runs TypeScript directly (imports need the .ts extension, no enums).

    line 190

≈ “Common” is an estimate: at least 1 in 5 of the 350,495 skill files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.

Keep what fits and drop the rest. Your version, ready for your agents.
Files
SKILL.md

tipee API via tipee-tools

tipee is a Swiss HR tool (employees, shifts, absences, activities). This repo exposes its API to agents, every operation but the few in EXCLUDED, for any tipee instance: @tipee-tools/core (the HttpApi generated from tipee's OpenAPI document, the derived client, the operation catalogue, errors), @tipee-tools/mcp (one MCP tool per operation, built from the catalogue, a *_many batch tool for a few, plus check_setup and update_plugin), and the Claude Code plugin in plugins/tipee that bundles the server. The user-facing skill lives in plugins/tipee/skills/tipee; this one is for developing the repo.

Guardrails

  • Writes exist now. Which tools a user gets, and which need approval, is decided in the Claude client; the server only annotates reads as read-only and every write but a create as destructive, and each write's description asks Claude to confirm first (Claude Desktop never loads the plugin's skill). Don't add server-side gates or deny lists. The one exception: EXCLUDED in packages/core/scripts/spec.ts leaves operations out of the generated API. resources.grant-roles and resources.revoke-roles would let Claude raise anyone's rights, its own integration's included; credentials.update-must-change-password is account security; schedule-templates.delete would rewrite history (next point). The last two are still in tipee's preview and listed ahead: a route the document lacks is skipped. A test keeps them all out.
  • Shift templates are history. Old templates are referenced by past plannings; never delete or modify them (that rewrites who worked when). A new need means a new template.
  • Personal data. Schemas are generated from the API document and pass through what tipee returns; tipee redacts what the integration may not see. Never commit real responses — fixtures are anonymised (the fictional company "Acme").
  • The API key is a secret: only in packages/mcp/.env or the Claude app's own settings, never in chat, commits or CI. Rotate it in the tipee admin if it leaks.

Running the server

pnpm mcp runs it on stdio from source; configuration in packages/mcp/.env (TIPEE_INSTANCE, TIPEE_API_KEY). Plugin users get the prompt from Claude Code instead. claude --plugin-dir ./plugins/tipee loads the plugin for development; pnpm build refreshes the bundle it runs.

Getting API access (the trap)

The API is off until an admin with the "Responsable API" role turns it on at /admin/instance/integrations/; integrations, their keys and their rights are then managed at /hr-core/integrations. The full rights list lives in plugins/tipee/skills/tipee/roles.md.

The key belongs to an integration — a service account created like an employee, given roles. Until it has the authorization Configurations générales → "Se connecter avec des applications externes", every call answers HTTP 401 {"message":"Tipee.api.token_rights_missing"} (not 403 as the docs say). No Planning role fixes that, and regenerating the key doesn't help. A wrong key gives "Le jeton fourni est invalide.".

Reads also need: Planning → "Accéder au module Planning" + "Voir les plannings"; Cœur RH → "Accéder au module Cœur RH" + "Voir les collaborateurs". Writes need Planning → "Planifier". Pay-related fields come back as {"redacted": "forbidden"}.

API facts that differ from the docs

Docs: https://api.tipee.ch/ (index https://api.tipee.ch/llms.txt, OpenAPI https://api.tipee.ch/openapi/<version>.json). Every endpoint is POST https://<instance>.tipee.net/api/... with a JSON body and headers Authorization: Bearer, Tipee-Version: <version> (TIPEE_API_VERSION, the vendored document's version), Accept: application/json.

  • Date-time intervals carry no seconds: 2026-09-07T23:00/2026-09-08T00:00 (the docs' examples show seconds). Template hours are 23:00/PT1H.
  • Date ranges can be open: 2026-08-01/-, -/2018-12-31.
  • Any value the integration may not see becomes {"redacted": "forbidden" | "confidential"} in place of a string, number or object.
  • Durations can carry negative parts (PT-15M); some templates have PT0S.
  • Pagination (resources.list): send pagination: {limit, next_token} explicitly (next_token: null first), explicit orders ({key: "resource.attribute", attribute: "last_name", direction: "asc"}), and identical filters/orders on every page or tipee answers 422. The cursor can be non-null on the last full page (the next page is empty).
  • Team filter: {key: "resource.team", value: {teams: [id], recursive: true}}.
  • Rate limits are generous (500-token bucket, 4/s). tipee guarantees that an error status (4xx or 5xx) changed nothing. Every operation is a POST, so the client retries reads (*.list, *.show*) on HTTP 408, 5xx and network failures, and anything on 429, 503 (maintenance) and 508 (a concurrent change, which tipee says to replay), waiting at least the Retry-After up to 10 s (resendable in TipeeClient.ts). A write whose answer was lost (a timeout, a broken connection, a gateway's 502 or 504) may have been applied: it is never sent twice and its error says to read it back. Each attempt times out after 20 s and a whole call after 50 s (MCP clients give up near 60 s); an attempt that timed out is not sent again.
  • Bulk writes: Claude used to make one call per day for a month of shifts. when takes a date interval or an RRULE, and the deletes take many ids; the descriptions, the instructions and the plugin skill say so. For edits that differ per item, BATCHED operations (packages/mcp/src/Batch.ts) get a <name>_many tool: up to 50 items, sent one after another through invoke, stopped at the first failure (tipee's per-request atomicity makes the report exact) or after 30 s, each item recorded as a call of its operation via the batch. Add an operation there only when telemetry shows bulk use.
  • *.tipee.net has a wildcard DNS record: a mistyped instance never fails with ENOTFOUND but answers HTTP 410 {"error":"instance_not_found"}.
  • Error messages quote tipee's whole answer and the HTTP status: never trim or paraphrase what tipee said, the agent acts on it.
  • Versions are date-based and supported ≥ 6 months after the next release; subscribe to the changelog on https://api.tipee.ch/.

Generated code

packages/core/spec/ holds tipee's OpenAPI document (one file, the pinned version). pnpm generate runs @effect/openapi-generator on it, through a JSON Patch built in packages/core/scripts/generate.ts: mark every request body required (tipee wants a JSON body even when empty); add to a few descriptions what tipee's document leaves out (pagination, the integration kind, the timecheck date range, an absence's percentage, a schedule create's empty answer) and name tools instead of routes; add orders and pagination to the required keys of ListResourcesQuery; let map-typed response properties also be [] (PHP's empty map); drop example(s); turn nested and/or filters into plain objects tipee validates; close request objects with additionalProperties: false, which shortens their schemas but refuses nothing (decoding drops unknown keys; the tools are Tool.Strict, which refuses them); turn enums only answers carry into strings listing the known values (tipee adds values within a version; request enums stay closed); remove the excluded operations. Dropping examples, cutting filters and closing objects keep the tool definitions small, since Claude Desktop loads all of them into every chat. A description rewrite that no longer changes anything fails the generation: tipee reworded the text, so the patch needs a look. It writes packages/core/src/generated/TipeeApi.ts — committed, never edited, freshness-checked by pnpm verify.

Keeping up with tipee: .github/workflows/spec-refresh.yml runs pnpm spec:refresh --bump every Monday. The script (in packages/core/scripts/refresh.ts) finds the newest stable version in llms.txt, downloads its document over the vendored one (or, for a new version, replaces the file and moves TIPEE_API_VERSION), regenerates, rebuilds and prints the operations and schemas that changed. The workflow opens or updates the PR (spec-refresh, or spec-move-<version> for a new version), with the version bumped: minor when operations were added, patch otherwise, and a needs-major label when one disappeared or was renamed, since tool names are the public surface. The routine: refresh PR → review the summary and the generated diff (fix or drop patches in generate.ts, add a fixture for a new shape) → merge, which releases it. Run pnpm spec:refresh locally (without --bump) to do the same by hand. Operations.ts reads the generated HttpApi with HttpApi.reflect and derives tool names from paths; the MCP package turns each entry into a strict, titled Tool.dynamic. Failure messages end with their next step (explain in Invoke.ts): Claude Desktop has no skill to look fixes up in. Spec-versus-reality fixes belong in the patch, nowhere else.

Repository notes

  • ARCHITECTURE.md describes the design (Effect 4 core, an MCP server that the plugin bundles, the same bundle as the Claude Desktop extension, the repo as its own marketplace) and what is not planned. Check it before adding a distribution channel or a configuration source.
  • Effect 4 is stable, pinned exactly (see packages/core/package.json); the effect-v4 skill in .claude/skills lists the idioms and v4 gotchas. Read Effect's sources in packages/core/node_modules/effect/src (exact version; pnpm does not link effect at the root) and its agent docs in packages/core/node_modules/effect/AGENTS.md and .../effect/ai-docs rather than memory.
  • TypeScript 7 (native compiler) with @effect/tsgo: pnpm install runs effect-tsgo patch, after which tsc and the type-aware lint report Effect diagnostics (for example preferTypedSchemaDecoder). Fix them rather than silencing them; severities live in each package's tsconfig.json.
  • Dependencies: Renovate (renovate.json) opens grouped weekly PRs for npm and GitHub Actions (pinned to digests), with a one-week cooldown; pnpm-workspace.yaml enforces minimumReleaseAge, no trust downgrades and no exotic sub-dependencies. Renovate moves effect and the @effect/* packages (except @effect/tsgo) together as one group; check that PR against the effect-v4 skill. @effect/tsgo, oxlint, oxlint-tsgolint and TypeScript move together as the TypeScript toolchain. No Dependabot: its updater cannot run pnpm 12.
  • Releases: the version lives in plugins/tipee/.claude-plugin/plugin.json and SERVER_VERSION only (the packages carry none, and core and mcp are private). A change to what ships bumps both; verify.yml fails a change under a version already tagged, and on main releases an untagged version from the .mcpb it built. It also runs plugins/tipee/scripts/smoke.ts on the committed bundle with Node 22.19.
  • No build step: Node 24 runs TypeScript directly (imports need the .ts extension, no enums). The only build is pnpm build, which bundles the server into plugins/tipee/server/ (the plugin is the workspace package @tipee-tools/plugin) — committed, and checked for freshness by pnpm verify.
  • Tasks run through Turborepo (turbo.json): check, test, build per package, cached; transit nodes propagate source changes between workspace packages; lint:check and format:check are root tasks. Run a single package with pnpm exec turbo run test --filter=@tipee-tools/mcp.
  • Tests: @effect/vitest + MSW. packages/core/test/handlers.ts is a fake tipee that enforces the real rules (401 bad key, 422 bad pagination) — assert on output, not on requests. Other packages import it from @tipee-tools/core/testing. it.effect runs on the test clock: wrap a call that retries in settled (test/answers.ts), which steps the clock until it finishes. One TestClock.adjust is not enough: MSW answers on the real event loop, so the adjust can pass before a retry's sleep exists.
  • pnpm fix applies the oxlint/oxfmt fixers and rebuilds the bundle; pnpm verify only checks (CI and the pre-commit hook rely on that split); every disabled rule is commented in oxlint.config.ts (notably unicorn/no-null: tipee's wire format needs literal null).

Download now (ZIP)

Does it work?

Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.

No reviews yet

People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.

  • It worked
  • Partly
  • It didn't
What did you use it for? e.g. Reviewing pull requests in a Rails app

Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.

Your trail

Files you open will collect here, so you can find them again.

Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.

Now do this for your own.

Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.