agentleFS
eprouvezeeprouveze/claude-skills/skills/salesforce-reports/SKILL.md

salesforce-reports

Skill0 starsChanged 5 months agoMITView on GitHub

Create, clone, read, run, and delete Salesforce Reports from the command line via the Analytics REST API, driven by the Salesforce CLI (`sf`). Org-agnostic — works against any org you've authed with `sf`. Includes a `--setup` flow (installs the sf CLI if missing, saves a default org/API version, and an optional Global Company filter for GAM roles). Use when the user says "create a Salesforce report", "clone a report", "generate a report via sf CLI", "list/run/delete reports", "report API", or "Analytics REST reports".

  • Reads credentials

The file

We split this skill into the rules it gives an agent

1 rule. About 0 are common, 0 are distinctive, and 1 is 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.

  • 1

    Very specific

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

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

    sf CLI presence: If sf is missing, setup offers to install it (npm → Homebrew → yarn, whichever is present).

    line 54

≈ “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

Salesforce Reports

Manage Salesforce Reports (the analytics object, not deploy/package "report" status commands) from the CLI. There is no native sf report create command — report CRUD lives in the Analytics REST API (/services/data/vXX.0/analytics/reports). This skill wraps that API through sf api request rest, which is the only path that authenticates correctly with the CLI's (masked) access token.

Everything routes through one script: scripts/sfreport.sh.

Quick start

S=~/.claude/skills/salesforce-reports/scripts/sfreport.sh

"$S" setup --org org62        # installs sf CLI if missing, saves config, checks auth
"$S" list                     # all reports you can see
"$S" types                    # report types (the 'type' you pass to create)
"$S" get  <id> --describe     # a report's metadata (filters, columns, format)
"$S" run  <id>                # run synchronously, return rows
"$S" clone --from <id> --name "Copy of X"   # most reliable way to create a report
"$S" create --type <apiName> --name "New" \
     --column <api> --filter '<col> <op> <value>' --group <api>   # report with columns/filters
"$S" delete <id> --yes        # delete (HTTP 204 on success)
"$S" --help                   # full reference

The script picks its target org from: --org flag → saved config (setup) → the sf CLI's configured target-org.

Setup

sfreport.sh setup is the front door:

  1. sf CLI presence. If sf is missing, setup offers to install it (npm → Homebrew → yarn, whichever is present). Non-interactively it installs without prompting.
  2. Default org + API version. Saved to ~/.config/claude-skills/salesforce-reports.env so you don't repeat --org every call. API version defaults to 62.0 (Analytics REST is stable there).
  3. Auth check. Confirms the Analytics REST endpoint is reachable; on failure it prints the sf org login web command to run.
  4. Global Company filter (GAM roles only — optional). See below.

Non-interactive form for scripts/CI:

"$S" setup --org myorg --api 62.0 --check-only      # check, don't write config
"$S" setup --org myorg --global-company "NTT, Inc." --gc-column Account.Global_Company__c

Global Company filter (GAM roles)

A Global Account Manager scopes reports to a single global parent account. This skill can re-point that filter on any clone so you don't hand-edit metadata:

"$S" clone --from <id> --name "NTT Pipeline" \
      --gc "NTT, Inc." --gc-column Account.Global_Company__c

Configure a default once at setup (GLOBAL_COMPANY + GC_COLUMN_DEFAULT) and every clone inherits it; override per-call with --gc / --gc-column. Resolution order for the value: --gc arg → $GLOBAL_COMPANY (env or saved config).

This is GAM-specific. Any other role can ignore it entirely — leave both blank at setup and the skill never touches report filters. To discover the right column on a report:

"$S" get <id> --describe | python3 -c \
  'import sys,json;[print(f["column"]) for f in json.load(sys.stdin)["reportMetadata"]["reportFilters"]]'

How creation actually works

Two create paths, in order of reliability:

  • Clone (recommended). POST /analytics/reports?cloneId=<id> with the source report's full reportMetadata (renamed). The skill fetches /describe, renames, optionally re-points the Global Company filter, and POSTs. This always yields a working report with columns and groupings already in place.
  • Create with metadata. POST /analytics/reports with a reportMetadata naming a reportType. Use types to find a valid reportType api name, and get <existing> --describe to discover that type's valid column / filter / grouping api names. The skill accepts:

    • --column <api> (repeatable) → detailColumns
    • --filter '<col> <operator> <value>' (repeatable) → reportFilters; the value is the remainder of the string, so spaces/commas are fine (--filter 'StageName equals Closed Won'). Operators: equals, notEqual, lessThan, greaterThan, contains, startsWith, etc.
    • --group <api> (repeatable) → groupingsDown (required for SUMMARY/MATRIX)
    • --boolean-filter '<expr>' → reportBooleanFilter (e.g. '1 AND (2 OR 3)')
    • --gc <value> --gc-column <api> → adds the GAM Global Company equals-filter With no --column, create still produces an empty stub. Clone remains the easiest path when you want to start from an existing report's full layout.
    "$S" create --type Opportunity --name "My Q3 Pipeline" --format SUMMARY \
          --column StageName --column Amount --column CloseDate \
          --filter 'StageName equals Closed Won' --filter 'Amount greaterThan 50000' \
          --group StageName

Known gotchas

  • Clone still needs a metadata body. POST ...?cloneId=<id> with a bare {} returns BAD_REQUEST: "there is no metadata". You must POST the full reportMetadata. The skill handles this by fetching /describe first.
  • sf api request rest DELETE is finicky. A plain -X DELETE errors No 'mode' found in 'body' entry; -b '' and --body '{...}' don't help; an object-shaped header errors keyValPair.map is not a function. The working form (used internally) is -f <envelope.json> with header as an array of "k:v" strings and body: {"mode":"raw","raw":""}.
  • Don't curl with the CLI token. sf org display [--verbose] returns a masked 54-char access token; curl with it gives INVALID_AUTH_HEADER. Always go through sf api request rest, which authenticates internally.
  • API version. Defaults to 62.0. The CLI's default data API may be higher (e.g. 67.0) but Analytics REST report CRUD is verified on 62.0; bump with --api only if you've tested.

Anti-patterns

  • sf data delete record --sobject Report — fails with INSUFFICIENT_ACCESS_OR_READONLY even when the Analytics DELETE succeeds; the SObject path enforces different rights. Delete reports via the Analytics endpoint (sfreport.sh delete).
  • Hardcoding an org alias. The skill is org-agnostic; pass --org or save one via setup. Don't bake org62 into callers.
  • Treating sf commands | grep report hits as report CRUD. Those are package/deploy status commands (package version report, project deploy report). Unrelated.
  • Bare-create then expecting data. A create without columns is empty by design — clone when you want a usable report.

Validated patterns

  • Clone → verify returned 18-char Id → use/delete. Verified on org62: create HTTP 200, delete HTTP 204, post-delete get → NOT_FOUND.
  • setup --check-only as a CI/pre-flight gate before any report automation.
  • GAM scoping by re-pointing one reportFilters entry on clone, rather than rebuilding the report — preserves columns, groupings, and report type.

Self-improvement

This skill ships with a lightweight feedback loop (learnings.md). Adopt or ignore — the skill works without it.

Trigger a review when:

  • The user corrects a created/cloned report's filter, name, or scope (strongest signal — log immediately; 2–3 corrections on the same theme → promote to the body).
  • The sf CLI changes its body/auth handling (e.g. the DELETE envelope bug gets fixed — the case-delete-envelope.sh golden case is the canary).
  • A new Analytics REST behavior or error code surfaces.
  • learnings.md crosses ~100 bullets (consolidation time).
  • The skill mis-triggers or fails to trigger.

Consolidation pass (5–10 min, weekly or threshold-driven): each learnings.md entry gets one fate — apply (merge into Known gotchas / Anti-patterns / Validated patterns), capture (leave in the log), or dismiss (delete). Bump last-consolidated: in frontmatter. Golden cases that previously passed and now fail are the loudest signal to consolidate early.

Golden cases live in golden/ — run ORG=<sandbox> golden/run-all.sh before changing the script.

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.