Until now there were two ways to change an app's settings: edit onvibe.json and deploy it, or call a tool — set_public_paths, add_allowed_email, create_cron, and friends. Both worked. That was the problem.
Two ways to say the same thing is one way too many
When config can change through two doors, the file in your project stops being the truth. An assistant that just downloaded your onvibe.json, then called a tool, is holding a document that no longer matches what's live — and the next deploy either fails or quietly reverts something. Worse, an assistant regenerating the file "from memory" can drop a setting it never knew about.
So config now has exactly one door: onvibe.json.
{
"version": "d2a37fc5c623712a", // the lock — keep it as you received it
"title": "My Book Club",
"access": {
"policy": "signup", // public | signup | allowlist | password
"publicPaths": ["/", "/d/*"], // routes anonymous visitors can reach
"allowlist": ["ana@example.com"] // only under "allowlist"
},
"crons": [
{ "name": "daily-digest", "schedule": "0 9 * * *", "path": "/cron/digest" }
],
"security": { "frame": "deny" }
}
The cycle is always the same: download → edit → deploy. get_config hands you the live document with a version hash; you change what you want, keep the hash, and deploy the file. If anything moved since you downloaded it, the deploy is rejected instead of overwriting settings you never saw. You can't lose config by accident, because you can only apply a file you based on the current one.
What went away
Seven tools disappeared, each replaced by a field you can read in the file:
| Gone | Now |
|---|---|
set_public_paths |
access.publicPaths |
add_allowed_email · remove_allowed_email · list_allowed_emails |
access.allowlist |
create_cron · delete_cron · list_crons |
crons |
Scheduled jobs get the biggest cleanup. They used to have two lifecycles — jobs declared in the file, reconciled on every deploy, and jobs created through the API, invisible to it. A job could reappear after you deleted it, or survive a deploy that removed it from the file. Now there's one set of jobs: whatever the deployed file says.
Two things about crons are not config, so they stayed as tools: run_cron triggers a job once for testing, and get_project reports each job's schedule, next run and last run. Defining is declarative; running and observing are not.
One tool survived on purpose. set_access_policy is still there for the shared password of policy: "password" — a secret, and secrets never belong in a file you commit. Everything else it used to do now happens in onvibe.json.
The principle underneath
We're drawing a line that we'll keep drawing:
- Configuration is a file. Readable, diffable, reviewable, and identical whether a human or an assistant edits it.
- Secrets are never in that file. Environment variables and the shared password are set separately, and never echoed back.
- Tools are for building and operating: write code, deploy, check, query, read logs, snapshot, roll back.
The upside for anyone driving onvibe through an assistant is fewer tools to choose between and one obvious answer to "how do I change this?". The upside for us is that as onvibe grows a web dashboard and a CLI for hand-written code, every one of those surfaces edits the same document — instead of each growing its own set of switches.
Full reference: the declarative config doc below.