Workflow

The swc CLI: from your code to a tested collection

swc is the Swastik Codes command-line tool. Point it at a backend project and it finds the API routes in the code: methods, paths, path variables, query parameters, request body fields and which routes need a login. It saves them as a collection in your account, ready to send from the web app or the desktop app. When the code changes, swc sync updates the same collection and keeps the tests and examples you added in the app.

Get started freeSign inOpen the app

swc bridge lets the web app send requests to localhost and your private network from your own computer.

The same binary runs collections from the terminal or a CI job with Newman-style flags, load-tests them, converts between formats and records traffic through a local proxy.

Install

swc is a single executable with nothing else to install. It runs on Linux x64 (any distribution) and Windows x64. macOS builds are coming.

Linux

Shell
curl -fsSL -o swc https://swastik.codes/download/files/swc-linux-x86_64
chmod +x swc && sudo mv swc /usr/local/bin/
swc version

Windows (PowerShell)

POWERSHELL
Invoke-WebRequest https://swastik.codes/download/files/swc-windows-x86_64.exe -OutFile swc.exe
.\swc.exe version

Move swc.exe to a folder on your PATH to run it from anywhere. To check a download, compare it with swc-SHA256SUMS: run sha256sum -c swc-SHA256SUMS --ignore-missing on Linux, or Get-FileHash swc.exe in PowerShell.

No install: scan a GitHub repository

To try it without installing anything, open Import → GitHub repo in the web app, paste a public repository (optionally a branch and a folder such as backend), and Swastik Codes reads its routes on our server with the same scanner and shows the collection before you import it. The code is downloaded, read and deleted right away; nothing in it is run. For private repositories and to keep the collection in sync as the code changes, use the CLI below.

Set up a project in one command

Run swc init in your project's folder. It walks you through four steps:

  1. Log in. Paste an API key. Create one in the app: click your avatar, then Account settings → API keys (your email must be verified). The key is saved in your user config file, readable only by you.
  2. Choose a workspace. Pick one of your workspaces or create a new one.
  3. Choose a collection. Create a new collection, or update one you already have.
  4. Scan and upload. swc reads the code, builds the collection and saves it.
Text
$ swc init
✓ logged in as you@example.com
✓ 24 requests (11 GET, 7 POST, 3 PUT, 3 DELETE) from fastapi (24); 38 files in 61 ms
Workspace:
   1) My Workspace  (personal)
   2) Create a new workspace
Choose 1-2: 1
Collection:
   1) Create a new collection
Choose 1-1: 1
New collection name [Shop API]:
Base URL for requests [http://localhost:8000]:
✓ saved "Shop API"

init writes a small .swc.json file that links the folder to the collection. Commit it, and everyone on the team syncs to the same collection.

What the scan finds

swc scan reads the source code and never runs your project. It detects these frameworks:

LanguageFrameworks
PythonFastAPI (routers, Pydantic models), Flask (blueprints, MethodView), Django and Django REST Framework (urls.py, routers, ViewSets, serializers)
JavaScript / TypeScriptExpress, Fastify, Koa, Hono, NestJS (controllers, DTOs), Next.js (app and pages API routes), Elysia
PHPLaravel (route files, resources, groups, validation rules), Symfony, Slim
Java / KotlinSpring (request mappings, @RequestBody DTOs), JAX-RS, Micronaut
Gonet/http, Gin, Echo, Fiber, chi, gorilla/mux
RustAxum, Actix Web, Rocket
RubyRails (routes.rb resources, namespaces, strong parameters), Sinatra
C#ASP.NET Core (controllers and minimal APIs)

For each route the collection gets:

  • a request in a folder named after its router, controller or tag, with a readable name;
  • {{baseUrl}} plus the path, with path variables such as :id ready to fill in;
  • the query parameters the code reads, and a JSON, form or multipart body with the fields it expects, typed as strings, numbers, booleans, emails and so on;
  • collection-level Bearer auth for routes that need a login, and a login request whose test script saves the token into a variable;
  • an environment with baseUrl taken from your .env port or the framework's default port.

To look before saving anything, list the routes with swc scan --routes, or write the collection to a file with swc scan -o api.json. Add --format postman for a Postman v2.1 file.

Keep the collection in sync

Shell
swc sync            # re-scan and update the linked collection
swc sync --dry-run  # show what would change, save nothing
swc sync --prune    # also remove requests whose route is gone from the code

sync matches requests by method and path. A request whose route still exists gets the method, URL, parameters and body fields from the code, and keeps everything you added in the app: tests, scripts, examples, auth, settings, and the name and description if you edited them. New routes are added to their folder. Routes that disappeared are listed, and removed only with --prune. Requests you created by hand in the app are never changed.

The collection is saved with its revision, so if someone edits it in the app while sync runs, sync merges into their version instead of overwriting it.

Keep the workspace in Git

Shell
swc workspace pull api/      # write every collection, environment and the globals as JSON files
git add api && git commit -m "API: add the refunds endpoint"
swc workspace push api/      # save the edited files back to the workspace
swc workspace status api/    # what push would change, without saving

pull writes the same layout as Export workspace in the app: a swastik.json manifest, one pretty-printed file per collection and environment, and globals.json, so every change is a readable diff in a pull request and the folder imports in the app too. A collection keeps its file name when it is renamed. Secret values and current values are never written to disk, and a blank secret in a file keeps the value saved in the account.

push saves only the files that changed, each against the revision it was pulled at. If someone edited the same collection in the app since, push stops with a conflict instead of overwriting their work: pull, merge and push again, or pass --force. pull never overwrites a file you edited and have not pushed yet. push never deletes anything in the account.

Reach localhost from the web app

The web app sends requests from Swastik Codes servers, so on its own it cannot reach localhost, your LAN, Docker networks or VPN-only hosts. swc bridge fixes that without a browser extension or CORS settings:

Text
$ swc login
$ swc bridge
swc bridge: requests sent from https://swastik.codes/app as you@example.com run on this computer ("dev-laptop").
✓ connected; waiting for requests
  GET http://localhost:8000/health → 200 (4 ms)

Then click Local bridge in the app's status bar and switch it on. Requests and collection runs from that browser now run on your computer, and the bridge prints each one. Switch it off to go back to the cloud proxy.

  • Only your account. The bridge signs in with your API key and takes work only from your own signed-in sessions. No website can talk to it: it opens no port on your computer and connects out to swastik.codes.
  • No files unless you say so. Form-data and binary bodies cannot read files from your disk unless you start it with --allow-files.
  • One at a time. Starting a bridge on a second computer takes over from the first one, which stops.
  • WebSocket, gRPC and other protocol connections still go through the cloud. For those, use the desktop app.

Catch breaking API changes before they ship

swc diff compares the API in your code with an earlier version of it, from a git branch or a saved snapshot, and tells you which changes break existing clients:

Text
$ swc diff --base origin/main
API changes against origin/main: 3 breaking, 0 warning(s), 1 other

✗ BREAKING  DELETE /orders/{order_id}  endpoint removed  (main.py:20)
✗ BREAKING  GET /orders/{order_id}  path parameter `order_id` changed type from int to string  (main.py:13)
✗ BREAKING  POST /orders  new required body field `coupon` (string); existing clients do not send it  (main.py:17)
+ info      GET /health  endpoint added

It flags as breaking: a removed endpoint, a path parameter with a new type, a query parameter or body field that is new and required (or became required), a changed field type, an allowed value that was removed, a different body format and an endpoint that now needs authentication. Removed request fields are warnings, because strict validators may reject clients that still send them. New endpoints and optional fields are listed as info. Renaming a path parameter ({id} to {user_id}) is not a change to clients.

  • --base <revision> compares with any branch, tag or commit; your working tree is never touched.
  • --snapshot api.json saves the current routes, and --against api.json compares with them later, without git.
  • --format markdown writes a table for a pull-request comment, --format json for your own tooling.
  • --fail-on breaking (the default) exits with status 1 when something breaks; warning, any and never change that.

swc diff reads routes, parameters and request bodies from the code. It does not see response bodies, so a renamed response field is not reported.

Comment API changes on every pull request

This GitHub Actions workflow posts the report on each pull request and fails the check when a change would break clients:

YAML
name: API changes
on: pull_request
permissions:
  contents: read
  pull-requests: write
jobs:
  api-diff:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
        with:
          fetch-depth: 0
      - name: Install swc
        run: curl -fsSL -o swc https://swastik.codes/download/files/swc-linux-x86_64 && chmod +x swc && sudo mv swc /usr/local/bin/
      - name: Compare with the base branch
        id: diff
        run: |
          set +e
          swc diff --base "origin/${{ github.base_ref }}" --format markdown > api-diff.md
          echo "status=$?" >> "$GITHUB_OUTPUT"
          cat api-diff.md >> "$GITHUB_STEP_SUMMARY"
      - name: Comment on the pull request
        env:
          GH_TOKEN: ${{ github.token }}
        run: gh pr comment ${{ github.event.pull_request.number }} --body-file api-diff.md --edit-last || gh pr comment ${{ github.event.pull_request.number }} --body-file api-diff.md
      - name: Fail on breaking changes
        if: steps.diff.outputs.status != '0'
        run: exit 1

Re-test only what changed

swc diff --base origin/main --collection <id> also lists the requests in your collection that call a changed endpoint, and swc run <collection> --affected-since origin/main --project . runs just those. Keep a full run on the main branch so nothing is missed.

Find undocumented and stale endpoints

swc inventory . --spec openapi.yaml --collection <id> compares the routes in your code, the operations in your API definition and the requests in your collection, and lists undocumented ("shadow") routes, documented routes the code no longer has, routes no request calls and requests for routes that are gone. --fail-on undocumented stops new undocumented endpoints in CI.

Check security in CI

swc security <collection> -e staging.json sends the collection's requests and reports risky CORS, missing security headers, insecure cookies, version banners, error details and sensitive fields, and endpoints that still answer when the request is sent without its credentials. --fuzz adds invalid inputs (wrong types, empty, very long, boundary numbers, missing fields) and reports 5xx errors and accepted invalid input. --fail-on high (the default) exits 1 when a finding reaches that level; --format json writes a machine-readable report. See Security checks and invalid input.

Mock servers on your computer

swc mock collection.json --port 4010 answers requests from the collection's saved examples, with the same matching and headers as the cloud mock servers.

Use your collection from an AI coding assistant

swc mcp collection.json -e staging.json serves the collection over the Model Context Protocol, so Claude Code, Cursor or VS Code can list, read, send and test its requests. It is read-only unless you add --allow-write, redacts secrets and auth headers, and logs every call (--log FILE). See Use your collection from an AI coding assistant.

Use it in CI

swc push --yes and swc sync --yes never ask questions and fail instead, so they can run in a pipeline. They read the API key from the SWC_API_KEY environment variable:

Shell
export SWC_API_KEY=swc_…     # store it as a CI secret
swc sync --yes
swc run <collection-id> -e <environment-id> -r cli,junit

swc run runs a collection with the same semantics as the collection runner and Newman-compatible flags: environments, globals, iteration data from CSV or JSON, folders, delays and timeouts. It loads a collection from a file, a URL or its id in your account, and reports to the terminal, JSON, JUnit XML or HTML. swc perf load-tests a collection with virtual users; see load testing.

All commands

CommandWhat it does
swc initlog in, choose a workspace and collection, scan, upload
swc scanfind the routes and write a collection file
swc push / swc syncscan and save to your account, create or update
swc login / logout / whoamimanage the saved API key
swc workspace list | create | uselist, create or choose a default workspace
swc workspace pull / push / statuskeep a workspace as JSON files in a Git repository
swc collection list | create | uselist, create or choose a default collection
swc bridgerun the web app's requests on this computer (localhost, LAN, VPN)
swc difflist API changes since a git revision or snapshot; fail on breaking ones
swc inventorycompare endpoints in the code, the API definition and the collection
swc mockrun a mock server from a collection's saved examples
swc securitysecurity checks and (with --fuzz) invalid inputs; fail CI on findings
swc mcpserve a collection to AI coding assistants over MCP
swc runrun a collection (Newman-compatible flags)
swc perfload-test a collection
swc convert / swc importconvert Postman, OpenAPI, Swagger, HAR, Insomnia and cURL documents
swc codegenprint code snippets for requests
swc capturerecord HTTP and HTTPS traffic through a local proxy

Run swc help <command> for every option.

Frequently asked questions

Does swc run or upload my code?

No. It reads the source files on your machine and sends only the resulting collection (routes, parameters and field names) to your account. It skips dependency, build and test folders such as node_modules, vendor, venv and target.

What if it misses a route or gets a field wrong?

The scan reads code patterns, so routes that are built at run time (from a loop or a config file, for example) can be missed. Fix the request in the app; sync keeps your edits. Pass --framework to scan for one framework only, and -x to leave out paths such as ^/internal/.

Is the bridge safe to leave running?

It acts only on requests from your own account, prints every one, and stops when you press Ctrl+C. Anyone signed in as you could send requests through it, so sign out of shared computers, and delete the API key in Account settings if it leaks.

Is there a macOS build?

Not yet. On a Mac, you can run swc in a Linux container or virtual machine for now.

Does it cost anything?

No. The CLI is free, like the rest of Swastik Codes.

Try it on your own API

Swastik Codes runs in the browser and is free to use. Create an account to send requests, sync your workspaces and invite your team.