Skip to content

Latest commit

 

History

History
189 lines (129 loc) · 9.34 KB

File metadata and controls

189 lines (129 loc) · 9.34 KB

Contributing to Argent

Thank you for your interest in contributing to Argent! This guide covers everything you need to get started.

Table of contents


Requirements

  • macOS with Xcode installed (required for xcrun simctl and iOS simulator support)
  • Node.js 20.19+ (the lint toolchain's floor; the published package needs 20.12+)
  • The simulator-server and ax-service binaries in packages/native-devtools-ios/bin/ (arm64 macOS, installed separately via npx @swmansion/argent install)

Setting up the dev environment

  1. Fork and clone the repository:

    git clone https://github.com/software-mansion/argent.git
    cd argent
  2. Install dependencies (npm workspaces installs all packages at once):

    npm install
  3. Start the dev environment:

    npm run dev

    This builds the native devtools dylibs (if the private submodule is available, otherwise uses pre-built binaries), compiles the MCP TypeScript, patches ~/.claude.json to point at the local MCP, and starts the tool-server from source via ts-node. Press Ctrl+C to stop — the script automatically restores your global Argent configuration.

    To use a different port:

    PORT=4000 npm run dev

    Note: packages/argent-private is a private git submodule that holds the ObjC source for the native devtools dylibs. If you don't have SSH access to it, npm run dev will use the pre-built dylibs committed to the repository — everything else works normally.

That's it, no separate install steps per package are needed, except packages/docs. It is excluded from the workspace glob and keeps its own lockfile, so npm run lint from the root needs npm install run inside packages/docs first.


Project structure

This is an npm workspaces monorepo. All packages live under packages/:

Package Path Purpose
@argent/registry packages/registry Core library: dependency-aware service lifecycle, blueprints, tools, URNs
@argent/tool-server packages/tool-server HTTP API over the registry (port 3001). Registers all blueprints and tools
@swmansion/argent packages/argent Published bin shell — minimal dispatcher + bundled subcommands + native runtime assets
@argent/tools-client packages/argent-tools-client HTTP client + tool-server launcher shared by @argent/mcp and @argent/cli
@argent/mcp packages/argent-mcp MCP stdio protocol adapter — proxies Claude/Cursor calls to the tool-server
@argent/cli packages/argent-cli Shell CLI commands: argent run, argent tools, argent server, argent enable, argent disable, argent flags
@argent/installer packages/argent-installer Workspace setup logic: argent init, update, uninstall
@argent/skills packages/skills Markdown skill files (prefixed argent-*) that instruct AI agents how to use Argent tools
@argent/native-devtools-ios packages/native-devtools-ios Pre-built dylibs for iOS simulator injection (view hierarchy, network inspection). ObjC source lives in packages/argent-private (private submodule)

The tsconfig.json at the root uses TypeScript project references; tsconfig.base.json holds shared compiler options (strict, ES2022, etc.).


Building

Local development (recommended)

npm run dev

Builds everything and starts the tool-server from source. See Setting up the dev environment for details.

Full build

Build all packages at once using TypeScript project references:

npm run build

To build a specific package:

npm run build -w @argent/registry
npm run build -w @argent/tool-server

To build and bundle the distributable MCP package:

npm run build -w @swmansion/argent
# or, to also produce a .tgz tarball:
npm run pack:mcp

Running the project

For day-to-day development, use npm run dev (see Setting up the dev environment).

Production-like start (builds bundles first, then starts from compiled output):

npm run start

This builds the registry, then starts the tools server on port 3001.

Verify the tools server is up:

curl http://localhost:3001/tools

Running tests

Tests are written with Vitest. Each package has its own test suite.

Run tests for a specific package:

npm test -w @argent/registry
npm test -w @argent/tool-server

Run tests in watch mode during development:

npm run test:watch -w @argent/registry
npm run test:watch -w @argent/tool-server

Code style

  • TypeScript strict mode is enabled across all packages ("strict": true in tsconfig.base.json). All code must compile without errors.
  • Target: ES2022 with CommonJS modules (except @swmansion/argent which uses ESM).
  • Prefer explicit types over any. Use Zod schemas for runtime validation where the codebase already does so.
  • Keep commits focused. Prefix commit messages with a type: feat:, fix:, chore:, docs:, refactor:, test:. This feeds the auto-generated changelog on release.

Submitting a pull request

  1. Create a branch from main with a descriptive name (e.g. feat/add-screenshot-tool, fix/session-leak).
  2. Make your changes. Keep the scope of a PR small and focused — it's easier to review.
  3. Ensure the build passes:
    npm run build
  4. Ensure tests pass for the packages you touched.
  5. Check for dead code, in a tree with no compiled output:
    npx tsc --build --clean
    npm run knip
    --clean removes what tsc emitted; the few non-TypeScript assets npm run build copies into packages/tool-server/dist are left behind. Knip does not look at them, so the report is the same either way. Run it this way round, not straight after step 3. The gate is counted against an unbuilt tree, because that is what CI analyses; with packages/*/dist present knip finds fewer issues, so a built-tree run carries phantom headroom and can pass locally while the Dead Code job fails. This leaves the tree unbuilt, so run npm run build again before re-running any test suite. The gate runs at --max-issues 0, so the report must come back empty and there is no ceiling to raise: when knip names an export, type or class member you added, drop the export keyword if the symbol is still used inside its own file, or delete it if nothing uses it. A class member has no export keyword to drop, so it is delete or tag. When the only caller is somewhere knip cannot see — another workspace, because the unbuilt tree breaks cross-workspace edges, or the argent-private submodule, which CI does not check out — tag the declaration /** @public */ and name that caller in the comment. That last case is what Unused exported class members almost always is here: the three tagged members in packages/registry are each called from another workspace, and pass 2 reports all three the moment a tag comes off. Look for it before you delete. This gate stays green on a wrong delete either way, but the two cases differ after that: deleting a symbol another workspace calls turns npm run build and that workspace's tests red, so that mistake is caught, while deleting one only argent-private reaches breaks nothing here — it require()s the built dist/*.js, and CI never checks that submodule out.
  6. Write a clear PR title — it becomes part of the release changelog. Use the same prefix convention as commit messages (feat:, fix:, etc.).
  7. Open the PR against main and fill in the description with context on what changed and why.
  8. A maintainer will review and may request changes. Address feedback with new commits (don't force-push after review starts).

Questions?

If you're unsure about something, open a GitHub Discussion or leave a comment on the relevant issue before spending time on a large change.