appctl sync
Introspect your app and write .appctl/schema.json.
New users should usually start with appctl setup, which
helps choose the right sync source and then runs the matching sync path.
appctl sync [OPTIONS]Sources (pick exactly one)
Section titled “Sources (pick exactly one)”| Flag | Value | Page |
|---|---|---|
--openapi <URL|file> | OpenAPI 2/3 document | OpenAPI |
--django <dir> | Django project folder | Django |
--flask <dir> | Flask project folder | Flask source via appctl sync --flask |
--rails <dir> | Rails project folder | Rails |
--laravel <dir> | Laravel project folder | Laravel |
--aspnet <dir> | ASP.NET project folder | ASP.NET |
--strapi <dir> | Strapi v4 project folder | Strapi |
--supabase <URL> | Supabase or bare PostgREST | Supabase |
--db <CONN> | Postgres/MySQL/SQLite or MongoDB/Redis/Firestore/DynamoDB URL | SQL / datastores |
--url <URL> | site root for URL login | URL login |
--mcp <URL> | MCP server URL | MCP |
--plugin <NAME> | dynamic plugin from ~/.appctl/plugins/ | Plugins |
Common options
Section titled “Common options”--base-url <URL>— override thebase_urlwritten to the schema. Include any API mount prefix (for examplehttp://127.0.0.1:8001/api).--force— allow overwriting an existingschema.jsonand regeneratingtools.json. Required whenever a schema file is already on disk, except for the first sync in a new project. See When to use--force.--watch— keep polling an OpenAPI source and re-sync whenever the document changes. Watch mode treats each detected change as an intentional regeneration.--watch-interval-secs <N>— polling interval for--watch(default2).--doctor-write— runappctl doctor --writeimmediately after a successful sync.--auth-header '<Header>: <Value>'— for OpenAPI, used when downloading the spec over HTTP(S). The same header line is stored for HTTP tool calls and written to[target].auth_headerin.appctl/config.toml(replacing a previous value when it changed). Values can useenv:VARorBearer env:VAR(see OpenAPI); rememberenv:has no space after it. For other sources,--auth-headermainly sets schema metadata for the executor.--supabase-anon-ref <NAME>— name of the secret (keychain or env var) to use as theapikeyheader for Supabase.--login-url,--login-user,--login-password,--login-form-selector— URL login credentials and form hints.
When to use --force
Section titled “When to use --force”sync writes or refreshes two files in .appctl/:
| File | Role |
|---|---|
schema.json | Resources, actions, auth. You can edit it. |
tools.json | Flat list for the model; derived from the schema on each successful sync. |
If there is no schema.json yet, the first run only creates these files. If
schema.json already exists, another run would replace it and rebuild
tools.json. That is fine when the API or DB really changed, but it also
destroys any edits you made to the JSON, and a mistaken sync in the wrong
tree or a CI job could wipe a checked-in file. The CLI requires --force for
that overwrite.
Use --force when you are deliberately refreshing from the source: after API
or schema changes, in batch jobs, or with appctl app add ... --openapi ... when the app dir
already has a contract. Omit it for the first sync in an
empty .appctl/.
--force is only about local files, not TLS or auth; use
--auth-header and friends for HTTP.
Examples
Section titled “Examples”OpenAPI APIs
Section titled “OpenAPI APIs”appctl sync --openapi https://api.example.com/openapi.json \ --base-url https://api.example.com --forceWith a bearer token stored in an environment variable:
export API_TOKEN='...'appctl sync --openapi https://api.example.com/openapi.json \ --base-url https://api.example.com \ --auth-header 'Authorization: Bearer env:API_TOKEN' \ --forceWatch mode polls the OpenAPI document and regenerates tools when it changes:
appctl sync --openapi https://api.example.com/openapi.json \ --base-url https://api.example.com --watch --doctor-writeFramework projects during local development
Section titled “Framework projects during local development”These examples assume the application server is running on your machine.
# Django, with /api as the API mount prefixappctl sync --django . --base-url http://127.0.0.1:8001/api --force
# Flaskappctl sync --flask . --base-url http://127.0.0.1:5000 --forceDatastores
Section titled “Datastores”# Postgresappctl sync --db "postgres://reader:pass@db.acme.com:5432/shop" --force
# SQLiteappctl sync --db "sqlite:///tmp/shop.db" --force
# MongoDBappctl sync --db "mongodb://127.0.0.1:27017/shop" --force
# Redisappctl sync --db "redis://127.0.0.1:6379" --forceSupabase
Section titled “Supabase”# Supabaseappctl sync --supabase https://YOUR-PROJECT.supabase.co \ --supabase-anon-ref supabase_anon --force--watchcurrently supports OpenAPI sources.- Firestore uses Google ADC at runtime. Run
gcloud auth application-default loginfirst. - DynamoDB uses your normal AWS credential chain. For local DynamoDB, pass an endpoint in the URL such as
dynamodb://us-east-1?endpoint=http://127.0.0.1:8000.
Exit codes
Section titled “Exit codes”0— success; schema and tools were written.1— any failure, including: source unreachable, parse/introspection error, or existingschema.jsonwithout--force(the error text tells you to add--force).