Repository navigation
Conversation
Docs: - README/skills no longer claim create commands read JSON from stdin *only* — cli.GetBody also accepts CLI Shorthand args. Heredoc stdin is still the recommended form, and the "no --body/--data/-d" fact stands. - README: demote Manual installation / MacOS / Windows / Linux to subheadings under Installation so the hierarchy reads correctly. - setup-api-monitor.md: the scheduled target is the call ID, not the "monitor ID", matching the rest of that skill. Code: - skills: updateClaudeMD no longer swallows os.ReadFile errors. An unreadable-but-present CLAUDE.md was treated as empty and then overwritten, destroying its contents. Tests: - oauth: cover the reflected-XSS hardening in the auth callback handler. Both new escaping tests fail if html.EscapeString is removed. - skills: table-driven tests for resolveTarget (no flag, each flag, and every mutually-exclusive combination). - cli: TestAuthHookFailure was order-dependent — it needs a non-nil configs map and rsh-profile set, or it panics before reaching the auth hook. It now runs standalone. - cli: typo in TestLoadCache comment. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Restish upstream moved off msgpack/v2 for a decoder safety fix (security: update msgpack decoder to v3) as part of their v2 rewrite; we were still on v2.1.1, older than what they had before that switch. v3 keeps the same Marshal/Unmarshal signatures so this is a drop-in import swap. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
TestResolveTarget still called resolveTarget with 3 args and expected error strings without --claude-skills, left stale after the claude-skills feature merged a 4th parameter. This broke go vet/go test on this branch. Adds the claudeSkills field, updates the expected error text, and covers the --claude-skills path. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
- TestAuthHookFailure now cleans up the configs/authHandlers entries and rsh-profile setting it introduces, so later tests don't observe its side effects. - Close the httptest response body after reading it in the auth callback tests, matching normal net/http contract. - resolveTarget's error-path test cases now also assert the returned agent kind is agentCustom, fully specifying its error behavior. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
All four .goreleaser configs sort tags with -version:refname, so when multiple environment tags point at the same commit (e.g. qc/beta/qc-stable cut from the same develop HEAD), goreleaser's git-based tag detection picks whichever tag sorts highest rather than the one that actually triggered the run — silently baking the wrong version into main.version. Set GORELEASER_CURRENT_TAG to $GITHUB_REF_NAME so goreleaser always uses the triggering tag instead of inferring it from git state. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Live-tested all 8 claude-skills workflows plus the three embedded onboarding skills against a real apimetrics-qc account and org, and fixed every confirmed discrepancy: - list-call-results doesn't exist -> list-results-by-call, whose flags are --from/--result-category/--cursor/--limit, not --since/--before (also fixed on list-results itself). - run-call doesn't exist -> run-monitor <id> runs API, browser, and MCP monitors alike. - list-slos/get-slo/create-slo/update-slo/delete-slo don't exist. SLOs are one per project: get-project-slo/update-project-slo (creates if none exists)/delete-project-slo, scoped by include_tags/exclude_tags with no scope/scope_id field. Rewrote apimetrics-slo-review's model accordingly. - list-schedules-for-call doesn't exist -> list-schedules-by-call. - get-result's "always a summary" claim only holds for below-ANALYST callers; ANALYST+ (most project members) get the full request/response/timing/DNS/TLS object back by default. - project-bootstrap's "the CLI cannot create a project" claim was wrong reasoning (create-project-in-org exists as a flat command outside the `project` noun-group) even though it happened to be right in effect for non-admin accounts. Documented the org-admin path, and the previously-undocumented gotcha that creating a project does not grant the creator access to it (needs a follow-up create-project-access call). - bulk init's apimetrics:/<collection> scheme doesn't resolve -- it's a cosmetic example string in the CLI's own --help (bulk/commands.go) with no actual scheme-resolution logic behind it, and fails with a literal DNS lookup on host "apimetrics". Fixed the example in commands.go to a resolvable placeholder host, and pointed the skill at a real host+path instead. - Three embedded onboarding skills (skills/embed/*.md) referenced a nonexistent --api-key flag in their error-recovery sections, and setup-api-monitor.md additionally had the run-call/list-call-results bugs above plus a result.success/failure_reason shape that doesn't exist (real field is result_category, PASS/FAIL/WARN/ERROR/TIMEOUT/ QUEUED). performance-analytics and the shared operating-rules boilerplate were otherwise verified correct and left alone where no bug was found. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01YKRzfBhwWbRrARvJsbFnaY
…lk init example - Standardize on result_category as the PASS/FAIL/WARN/ERROR/TIMEOUT/QUEUED field everywhere (AGENTS.md, failure-investigation, incident-triage, project-bootstrap), matching the embedded skills and the rest of this PR. A separate result field carries a transport-completion value (e.g. COMPLETE), which is now called out explicitly where the two could be confused. - config-as-code: drop the redundant/inconsistent first bulk init example (it set url to a bare id without --url-template, contradicting the documented url/uri/self/link-or-url-template guidance) and keep the single --url-template form, which was confirmed working live. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01YKRzfBhwWbRrARvJsbFnaY
Bump shamaton/msgpack to v3
Address Copilot review feedback from PR #16
Several fixes from the previous commits were written as a diff against the prior (incorrect) text -- "there is no list-call-results (use list-results-by-call)", "the apimetrics:/<collection> scheme does not work", "there is no run-call" -- which only makes sense to someone who saw the old version. A fresh reader (a new agent invoking the skill, someone who never saw the prior draft) has no context for what's being negated. Rewrote all of these to state the current CLI surface directly and positively, and swapped the placeholder `<call-or-monitor-id>` positional argument name for `<monitor-id>`, matching this codebase's convention of "monitor" as the umbrella term for an API call/browser test/MCP test. Left alone the handful of pre-existing "there is no --api-key flag" / "there is no --body/--data/-d flag" warnings, which predate this PR, don't reference anything removed from these docs, and read fine standalone as guardrails against a very plausible wrong guess. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01YKRzfBhwWbRrARvJsbFnaY
--apimetrics-project-id does exist (confirmed live in get-project-slo and update-project-slo's own generated option schema), but it isn't the documented, general-purpose mechanism for targeting a different project. That's the global --project-id flag (registered in cli/cli.go, and what cli/config.go's "no active project" error tells users to pass), so point at that instead. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01YKRzfBhwWbRrARvJsbFnaY
commands.go:317's example used /monitors while the bulk init subcommand's own examples (line 346, pre-existing) use /users -- inconsistent for no reason. Match them. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01YKRzfBhwWbRrARvJsbFnaY
Fix goreleaser version mislabeling when multiple tags share a commit
- State facts directly instead of contrasting with what earlier skill text claimed (one SLO per project, list-results flags, run-monitor, project creation). - Remove the --api-key references from AGENTS.md and the embedded setup skills. - Drop get-project-slo from the list-envelope summaries. - slo-review: derive availability attainment from get-call-passfail-range/ get-call-passfail-total and latency from query-*-performance, keeping list-results for drilling into violations; add the same guidance to AGENTS.md. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01VcnM8iRzyY2ZEyNi6iyp28
- Drop the "not noun/verb groups" and "Do not invent --body" lines from the shared skill preamble, and the matching "There is no --body" line from the embedded setup skills. - skills.go: generated agent guide states the flat-command and stdin facts directly, matching AGENTS.md. - weekly-health-review: take pass/warning/failure counts from get-call-passfail-range instead of paging list-results and counting; keep list-results for failure detail. SLO attainment points at the slo-review method. AGENTS.md table row updated to match. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01VcnM8iRzyY2ZEyNi6iyp28
…e-cli-review # Conflicts: # skills/skills.go
… API-call only Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Describe it in the general case with <monitor-id> rather than as API-call only. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…lows
Verified every skill, AGENTS.md, and README example against apimetrics-qc
and fixed what the CLI and server actually do:
- result_category is PASS/SLOW/WARNING/FAIL (empty while queued; poll on
meta.result); --result-category silently ignores other values. Result
rows are {id, meta, timing}; there is no response_time/test/created.
- -f paths are rooted at the response envelope (body.), and must be quoted
for zsh; shorthand needs URLs quoted and </dev/null when non-interactive.
- MCP monitors need a Streamable HTTP endpoint and steps need wait_ms.
- SLO period is DAY/WEEK/MONTH; get-project-slo returns defaults when none
is stored; get-call-passfail-total's top-level stat.total is not a count.
- bulk: checkout does not record its project, push needs partial bodies,
and push reports success on failed uploads.
- Note deprecated v2 call commands and their v3 replacements while keeping
the commands production still lists.
- onboard now prints the eight workflow skills as well as the setup
guides, with a test; fix the root --help example's nonexistent command.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
account_id alone selects the grantee (defaulting to the caller) and email is an informational label; the top-level stat.total counts only uncategorised results, matching the legacy aggregation. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The CLI already caches refresh tokens and tries them before falling back to a browser login, but it never asked Auth0 for one: the scopes were "openid profile email", so every expired access token meant logging in again. Add offline_access to the scopes. Also log at debug level why a refresh was rejected before falling back, and correct the cache comment, which assumed the server never returns a new refresh token (it does under refresh token rotation). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
`apimetrics login --device` uses the OAuth 2.0 device authorization grant (RFC 8628): the CLI prints a URL and a short code, the user approves it in a browser on any device, and the CLI polls the token endpoint until they do. Unlike the browser login it needs no redirect to localhost:8484, so it works over SSH and in containers. The new oauth-device-code handler takes the browser login's parameters and cache key, so the token it gets is used by every later command, and it tries a cached refresh token first like the browser login does. The device endpoint is derived from the token URL (Auth0's /oauth/device/code) and the audience from the authorize URL's query string. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Address Copilot review: requestDeviceToken duplicated requestToken's HTTP call and its response parsing. Both now use postForm and a new parseToken helper in request.go. requestToken now also returns a body read error rather than ignoring it. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The test set a 1ms timeout against a 2ms mock delay. A context is only marked expired when its timer callback runs, so on a busy machine gock's 2ms timer could fire first, the mock replied 200 and MakeRequest returned no error. Reproduced locally under CPU load (13 failures in 6,000 runs). Use a 10ms timeout and a 10s delay: gock stops waiting as soon as the context is done, so the test is no slower. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ills
Verified against apimetrics-qc: run-monitor returns {call_id, context,
location_id, result_id, user}, and --from/--time reject a bare date
with a 4xx "Invalid request".
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
doRequestWithRetry derived each attempt's rsh-timeout context from req.Context(), but req had already been replaced with the previous attempt's request, so a retry after a timeout started with an expired context and failed immediately. Timeouts were never really retried. It also deferred every cancel until the function returned, which is before the caller reads the body. With -t set, any body larger than the transport's buffer was cut off with "context canceled" (4MB came back as 3,963 bytes). And with --rsh-retry 0 it returned early and skipped the timeout altogether. Each attempt now derives its timeout from the request's original context. A discarded attempt is released immediately, and the returned response's timeout is released when its body is closed. The retry loop also runs with no retries, so the timeout always applies. As a side effect, -v now logs the request and response with --rsh-retry 0 too. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Add device code login (apimetrics login --device)
Fix stale/incorrect CLI claims in skills and AGENTS.md
Fix flaky TestRequestRetryTimeout
Resolve conflict in cli/serviceaccount_test.go by keeping both the offline_access scope test and develop's device-code login tests. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Request offline_access so browser logins get a refresh token
ndenny
enabled auto-merge
October 19, 2026 21:46
neil-gall
approved these changes
Oct 20, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Merge to main