Skip to content

Setting up OpenAPI with Claude#169

Merged
leogdion merged 6 commits into
claude-promptfrom
107-108-openapi-setup
Jun 12, 2026
Merged

Setting up OpenAPI with Claude#169
leogdion merged 6 commits into
claude-promptfrom
107-108-openapi-setup

Conversation

@leogdion

Copy link
Copy Markdown
Member

No description provided.

leogdion and others added 3 commits June 11, 2026 16:28
Deletes .cursor/, .taskmaster/, .mcp.json, .env.example, and the
Task Master commands, agents, and guide under .claude/, and drops
the Task Master section from CLAUDE.md.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
swift-openapi-generator is managed as a mise tool (spm backend), not an
SPM build plugin; Scripts/generate-openapi.sh regenerates the client and
the output is committed under Sources/ClaudeKit/Generated. The config
filters to /v1/messages — the unofficial spec's `?beta=true` path
variants carry duplicate operationIds that fail generator validation.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
ClaudeKit wraps the committed OpenAPI-generated client (runtime +
URLSession transport deps only); it skips the shared swiftSettings
because InternalImportsByDefault rejects the generator's plain imports
in package-access API. AiSTKit bridges ClaudeKit and SyntaxParser and
is now a dependency of the skit executable. No new products.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@coderabbitai

coderabbitai Bot commented Jun 12, 2026

Copy link
Copy Markdown

Important

Review skipped

Auto reviews are disabled on base/target branches other than the default branch.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: f644e3ab-38ee-4a84-a143-bc636db32ff1

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch 107-108-openapi-setup

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@claude

claude Bot commented Jun 12, 2026

Copy link
Copy Markdown

Code Review: Setting up OpenAPI with Claude (#169)

Base branch: claude-prompt (not main) — this is Phase 1 infrastructure on top of another in-progress branch.


Overview

This PR implements Phase 1 of the skit analyze feature by:

  • Adding a ClaudeKit target with a committed OpenAPI-generated Claude API client
  • Adding an AiSTKit placeholder target that will bridge skit analyze to ClaudeKit
  • Using mise to manage swift-openapi-generator as a dev CLI tool (not an SPM build plugin), with generated code committed to the repo
  • Reorganizing .claude/ Task Master commands from a single CLAUDE.md to individual command files

The overall approach is sound. Committing generated code rather than using a build plugin avoids the InternalImportsByDefault/strict-concurrency conflicts and speeds up CI builds.


Issues

readlink -f portability in Scripts/generate-openapi.sh

SCRIPT_DIR=$(dirname "$(readlink -f "$0")")

The comment says "more portable way" but readlink -f requires GNU coreutils and does not work on stock macOS (readlink on macOS only supports -n). For a contributor who clones and runs this script on macOS without Homebrew coreutils installed, it silently returns an empty path. Replace with the portable POSIX alternative:

SCRIPT_DIR=$(cd "$(dirname "$0")" && pwd)

License header on generated files obscures the generator notice

header.sh prepends a 28-line MIT copyright block before the generator's own comment. The result in Client.swift is:

//  ... 28 lines of MIT license ...
//

import HTTPTypes
// Generated by swift-openapi-generator, do not modify.

The "do not modify" notice is buried below the copyright, and the copyright itself implies these are hand-authored files. Consider either skipping header.sh for Sources/ClaudeKit/Generated/ or moving the generator notice above the copyright block. As-is, a contributor maintaining the repo might not realize these are generated files on a quick scan.

x-api-key and anthropic-version headers are required: false in the spec

Both authentication headers are marked optional in openapi.json. The generated client therefore won't fail at compile time or even at call time if they're missing — the request will just fail with a 401 at runtime. This is an API spec fidelity issue (the headers are effectively required), but since they're controlled by whatever ClientMiddleware the caller injects, make sure this is documented clearly when AiSTKit is implemented in Phase 2.


Observations

Good: committing generated code over build plugin

The IMPLEMENTATION_STATUS.md explains why the build plugin approach was dropped (?beta=true path variants with duplicate operationIds fail validation). Committing the generated output is the right call here, and documenting the deviation from the original plan is appreciated.

Good: ClaudeKit target intentionally omits swiftSettings

The Package.swift comment explaining this is the right call — the generated import OpenAPIRuntime style clashes with InternalImportsByDefault. Worth keeping an eye on when the project upgrades to a Swift version where that feature is fully standard.

openapi.json contains full Anthropic spec (6428 lines) but only /v1/messages is generated

This is a deliberate choice to make future re-generation easier. Fine as-is, but consider adding a comment in openapi-generator-config.yaml explaining why the filter exists (the duplicate operationId issue), so future maintainers don't wonder why the full spec is there but only one path is generated.

.env.example deleted but ANTHROPIC_API_KEY will still be needed

The old .env.example was Task Master-focused, so removing it is reasonable. However, once skit analyze lands in Phase 2+, contributors will need an ANTHROPIC_API_KEY. Consider adding a minimal .env.example focused on that key before Phase 2 merges to main.

No tests

Expected for a pure infrastructure/scaffolding PR — AiSTKit.swift is explicitly a placeholder and ClaudeKit is generated code. No action needed here, but confirm the first Phase 2 PR includes tests for AnalyzerConfiguration and AnalyzerError.

AiSTKit uses package enum AiSTKit {}

Consistent with the project's package access modifier strategy. Good.


Summary

The only blocking item is the readlink -f portability bug in the generation script — a macOS contributor running it without GNU coreutils will get a broken path. The license header issue is a minor polish concern. Everything else looks well-thought-out. The deviation from the original plan (committed generated code vs. build plugin) is correctly documented in both the plan doc and the implementation status file.

SyntaxKit, CodeQL, and check-unsafe-flags only triggered on PRs into
main (or version branches), so stacked PRs like #169 (into
claude-prompt) skipped the build/test matrix entirely.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@claude

claude Bot commented Jun 12, 2026

Copy link
Copy Markdown

Code Review: Setting up OpenAPI with Claude (PR #169)

Overview

This PR lays Phase 1 of the skit analyze roadmap: it wires in the Anthropic Claude API client via swift-openapi-generator, adds two new SPM targets (ClaudeKit, AiSTKit), and ships a generation/regeneration script. The actual analyze subcommand is deferred to Phase 2. The scope is exactly right for an infrastructure-only PR.


✅ What's Well Done

  • accessModifier: package in openapi-generator-config.yaml is the correct choice — it keeps the generated client internal to the package without polluting the public API surface.
  • Committing generated code (Sources/ClaudeKit/Generated/) rather than running the generator at build time avoids build-plugin sandboxing headaches and is consistent with the plan document's stated rationale.
  • Scripts/generate-openapi.sh is clean and portable: graceful $SRCROOT fallback, mise env activation, post-generation formatting + license header pass. This is a solid dev-loop script.
  • ClaudeKit intentionally omits swiftSettings and the comment explains why (InternalImportsByDefault conflicts with the generator's plain import OpenAPIRuntime). Good defensive documentation.
  • report_exclude in .periphery.yml correctly excludes the generated directory so Periphery won't flag unused generated types.
  • Sources/ClaudeKit/Generated excluded from SwiftLint — correct, generator output doesn't need to conform to project style rules.
  • AiSTKit.swift placeholder keeps the target buildable with a package enum AiSTKit {} namespace stub and a doc comment that explains what's coming. This is the right pattern for scaffolding.
  • IMPLEMENTATION_STATUS.md is a well-structured living doc that records the plan deviation (CLI tool over SPM plugin) with clear rationale.

⚠️ Issues & Suggestions

1. openapi.json is large and will drift — consider a lock/hash

The full Anthropic OpenAPI spec (~large JSON, many paths) is committed, but the generator config filters to only /v1/messages. There's no mechanism to detect when the upstream spec changes and the committed file goes stale.

Suggestion: Add a SHA or version comment at the top of openapi.json, or add a Scripts/check-openapi-freshness.sh step to CI that compares a pinned hash. This is optional for Phase 1 but will matter once the tool is actively used.

2. mise.toml version skew with .swiftlint.yml version comment

mise.toml pins aqua:realm/SwiftLint = "0.62.2" but CLAUDE.md says SwiftLint 0.63.2. This skew can cause "lint passes locally but fails in CI" bugs.

# mise.toml — should match CLAUDE.md
"aqua:realm/SwiftLint" = "0.63.2"   # ← was 0.62.2

3. No .env.example — API key handling is undocumented at this phase

The plan mentions a ANTHROPIC_API_KEY-style environment variable, but .env.example doesn't exist yet (the diff shows it added but the file wasn't readable in this review). Future phases that implement AnalyzerConfiguration should document where the key is expected (env var vs. --api-key flag vs. keychain) before any code actually reads it.

Suggestion: Add a one-line comment in AiSTKit.swift or IMPLEMENTATION_STATUS.md capturing the decided credential source so Phase 2 implementers aren't guessing.

4. Package.swiftswift-openapi-urlsession is linked but unused until Phase 4

ClaudeKit already depends on OpenAPIURLSession in Package.swift. Since no transport is wired up yet (the client is generated but AiSTKit is a stub), this is dead weight that may cause build warnings on some platforms.

This is a minor point — the dependency is correct for the final shape — but worth noting so Phase 2 authors know the transport isn't configured yet.

5. CI does not verify the committed generated code is up-to-date

The generated files are committed, but nothing in CI runs Scripts/generate-openapi.sh and checks that the result matches the committed files. A developer could edit openapi.json and forget to regenerate.

Suggestion (Phase 1 follow-up or Phase 2 prerequisite):

- name: Verify generated OpenAPI client is up-to-date
  run: |
    ./Scripts/generate-openapi.sh
    git diff --exit-code Sources/ClaudeKit/Generated/

6. AiSTKit target has swiftSettings applied, but it depends on ClaudeKit which doesn't

If AiSTKit uses InternalImportsByDefault (part of swiftSettings) and imports ClaudeKit symbols, the package-access types from ClaudeKit are visible — but InternalImportsByDefault changes import semantics. Verify that AiSTKit's imports of ClaudeKit are spelled correctly once Phase 2 adds real code (they'll need import ClaudeKit not internal import ClaudeKit).


Security

No credentials are present in the committed files — the x-api-key references are in the OpenAPI spec (expected) and the generated client header types (correct). The key will be passed at runtime, not compile time. This is fine.

The openapi.json is a copy of an external API description, not a secret. No concerns here.


Test Coverage

None added, which is appropriate: this PR is pure infrastructure (generated code + build config). The plan correctly defers tests to Phase 6-7. No action needed for this PR.


Summary

Phase 1 is solid. The two blocking items before merging are the SwiftLint version skew in mise.toml and ensuring the CI stale-generated-code check is on the Phase 2 radar. Everything else is a good-to-have for later phases.

@codecov

codecov Bot commented Jun 12, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 79.97%. Comparing base (f0b4265) to head (e44053f).
⚠️ Report is 1 commits behind head on claude-prompt.

Additional details and impacted files
@@                Coverage Diff                @@
##           claude-prompt     #169      +/-   ##
=================================================
- Coverage          80.13%   79.97%   -0.16%     
=================================================
  Files                153      153              
  Lines               5209     5209              
=================================================
- Hits                4174     4166       -8     
- Misses              1035     1043       +8     
Flag Coverage Δ
spm 79.95% <ø> (-0.02%) ⬇️
swift-6.1 ?
swift-6.2 ?
swift-6.3 79.94% <ø> (-0.02%) ⬇️
ubuntu 79.94% <ø> (-0.16%) ⬇️

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

…cludes

Match MistKit's approach: swift-openapi-generator emits periphery:ignore:all
and swift-format-ignore-file comments into the generated files, header.sh
skips files carrying the directive, and the Periphery report_exclude is
dropped. SwiftLint keeps its directory exclude since file-level rules like
file_name fire at line 1, before any disable comment takes effect.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@claude

claude Bot commented Jun 12, 2026

Copy link
Copy Markdown

Code Review — PR #169: Setting up OpenAPI with Claude

Overview

This PR establishes the OpenAPI integration scaffolding for the skit analyze subcommand. It adds two new Swift targets (ClaudeKit and AiSTKit), commits generated OpenAPI client code for the Anthropic Messages API, wires a regeneration script, and cleans up superseded TaskMaster configuration files.


Architecture & Design

Committed generated code (good call)
The decision to manage swift-openapi-generator as a mise CLI tool rather than an SPM build plugin is well-reasoned and documented. Committing the generated output avoids the build-time plugin complexity and the InternalImportsByDefault incompatibility. The Scripts/generate-openapi.sh script + mise.toml entry gives a clear regeneration path.

swiftSettings exclusion on ClaudeKit
The comment in Package.swift explaining why swiftSettings is omitted from ClaudeKit is necessary — this is a non-obvious workaround and would confuse future contributors without it. Good.

Filter to /v1/messages only
Smart. The unofficial Anthropic spec has duplicate operationId entries on beta path variants; filtering to just the one endpoint needed avoids generator validation failures cleanly.


Potential Issues

x-api-key marked required: false in the spec
In openapi.json both x-api-key and anthropic-version are required: false. In practice, x-api-key is mandatory for every real API call. AiSTKit's implementation (arriving in issues #110#120) must ensure this header is always injected — likely via a ClientMiddleware. Worth a note in AiSTKit.swift or the relevant issue so it isn't accidentally omitted.

CI branch-filter removal
All three workflow files (SyntaxKit.yml, check-unsafe-flags.yml, codeql.yml) now run on all PR target branches, not just main. This is fine for this feature branch, but consider whether it's the intended permanent policy — it will run CodeQL and the full matrix on every draft PR regardless of target. If it's deliberate, a comment in the YAML would help future maintainers understand the intent.

No API key documentation after .env.example removal
.env.example was removed (it was TaskMaster-specific) and .mcp.json was cleaned up too. Once AiSTKit is functional, users will need to supply ANTHROPIC_API_KEY. There's no replacement documentation yet. A note in CLAUDE.md or a new .env.example specific to the skit/Claude workflow would prevent confusion.


Code Quality

Scripts/header.sh AWK change
The change from a simple first-line head check to an AWK scan of the leading comment block is correct — generated files may have the swift-format-ignore-file directive on line 2 or 3 (e.g. after // Generated by swift-openapi-generator). The AWK logic is sound: it exits on the first non-comment, non-blank line, so it won't scan the whole file.

AiSTKit.swift placeholder
The package enum AiSTKit {} namespace placeholder is minimal and appropriate. The doc comment clearly signals it's intentional scaffolding, not forgotten code.

openapi.json — large committed file
At 6 400+ lines this is the biggest file in the PR. It's the upstream Anthropic spec and should not be hand-edited. Consider adding a comment at the top of the file (or a README in Sources/ClaudeKit/) explaining its origin and how to update it, so future contributors don't edit it directly or wonder if it's auto-generated.


Cleanup Assessment

The mass deletion of .claude/commands/tm/ files, .taskmaster/CLAUDE.md, .taskmaster/config.json, and the three agent files is appropriate — these are all superseded by the built-in Task Master skills. No regression risk; they were Claude Code configuration, not source code.


Summary

Category Status
Architecture ✅ Sound, well-documented decisions
Build correctness ✅ Package.swift wiring looks correct
Generated code quality ✅ Excluded from linting/Periphery
Missing implementation ℹ️ Expected (AiSTKit is a placeholder)
x-api-key required enforcement ⚠️ Must be handled in future AiSTKit impl
CI scope widening ⚠️ Intentional? Worth documenting
API key docs gap ⚠️ Needs follow-up before AiSTKit ships

Overall this is solid scaffolding work. The three ⚠️ items are all low-risk for this draft PR but should be tracked before the implementation issues (#110#120) are merged.

The committed client is generated by swift-openapi-generator 1.12.2, so
require swift-openapi-runtime 1.12.0 and swift-openapi-urlsession 1.3.0
(the versions already pinned in Package.resolved) instead of 1.0.0, which
could resolve a runtime too old to compile the generated @_spi(Generated)
calls. Also record the openapi.json source repo, retrieval date, and
refresh command in generate-openapi.sh.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@claude

claude Bot commented Jun 12, 2026

Copy link
Copy Markdown

Code Review: Setting up OpenAPI with Claude

Overview

This PR introduces two new Swift targets — ClaudeKit (OpenAPI-generated Anthropic API client) and AiSTKit (bridge layer placeholder) — and wires them into the skit executable. It also cleans up Task Master AI tooling files and tightens CI trigger configs. The structural decisions are sound; a few items below warrant attention before merging.


What's Good

  • Committing generated code vs. SPM build plugin: The rationale is well-documented in Package.swift. Using swift-openapi-generator as a mise-managed CLI tool and committing output sidesteps the InternalImportsByDefault Swift 6 upcoming-feature conflict cleanly.
  • filter: paths: [/v1/messages] in openapi-generator-config.yaml: Necessary and correctly explained — the unofficial spec's ?beta=true variants produce duplicate operationIds that fail generator validation.
  • accessModifier: package: Right choice for an internal-only client target; prevents accidental API surface leakage.
  • Scripts/header.sh improvement: Scanning the leading comment block for swift-format-ignore-file rather than checking only line 1 is more robust for generated files.
  • SwiftLint exclusion for Sources/ClaudeKit/Generated: Correct and expected.

Issues & Suggestions

1. readlink -f not available on macOS — Scripts/generate-openapi.sh may fail for local devs

SCRIPT_DIR=$(dirname "$(readlink -f "$0")")

readlink -f is a GNU coreutils extension and not available on stock macOS (returns an error). This script would fail for any developer running it outside CI without coreutils installed via Homebrew. Replace with:

SCRIPT_DIR=$(cd "$(dirname "$0")" && pwd)

This is portable across macOS and Linux without extra dependencies.

2. The unofficial OpenAPI spec (laszukdawid/anthropic-openapi-spec) is a third-party mirror

The comment in generate-openapi.sh correctly identifies the source. However:

  • The spec version is 0.0.0, indicating it is informal/unofficial.
  • When AiSTKit is implemented, the anthropic-version header (currently required: false in the spec) should always be set to a pinned value (e.g. 2023-06-01) per Anthropic's API guidelines. Consider adding a constant for this in AiSTKit when the real implementation lands.

3. CI workflow branch filter removal

Removing branches: [main] from pull_request: triggers means CI now runs on PRs targeting any branch (e.g. feature branches merging into other feature branches). This is intentional here (this PR targets claude-prompt), but it's a standing change — confirm the team is okay with CI running on all PR targets going forward.

4. AiSTKit is an empty enum wired into skit

The placeholder is fine for keeping the target buildable. Just confirm that skit still builds and runs correctly with AiSTKit as a dependency of zero substance — particularly that no dead-import warnings or linker issues appear in CI.

5. The committed openapi.json is 6,428 lines (the full unofficial spec)

Only /v1/messages is used (filtered in the generator config), but the entire spec is committed. This means future spec updates will produce large noisy diffs. Consider trimming the committed spec to only the paths and components actually needed — or accept the noise and document that openapi.json is a verbatim snapshot.

6. mise.toml pins SwiftLint at 0.62.2; CLAUDE.md says 0.63.2

Minor inconsistency worth resolving to avoid confusion.


Test Coverage

No tests are added, which is expected for a placeholder target and generated client. When AiSTKit implementation lands (issues #110#120), ensure:

  • Unit tests mock ClaudeKit.Client via the APIProtocol (the generated protocol makes this straightforward)
  • Integration tests for the full skit analyze flow are added

Summary

The architecture is correct and the tradeoffs are well-reasoned. The one actionable blocker before merging is the readlink -f portability issue in generate-openapi.sh — it will silently break for macOS developers. The rest are observations for the implementation issues to pick up.

@leogdion leogdion marked this pull request as ready for review June 12, 2026 19:52
@leogdion leogdion merged commit 07f505b into claude-prompt Jun 12, 2026
16 of 18 checks passed
@leogdion leogdion deleted the 107-108-openapi-setup branch June 12, 2026 19:53
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant