Skip to content

Changelog

What changed in the jiayang CLI and in each SDK, from one release to the next, newest first. The platform itself changes without releases, and the docs say what it does today.

jiayang, from npm, Homebrew or the install script. Its docs.

Changed:

  • jiayang schedule off says when it cancelled a run that was waiting to go, from jiayang schedule run or because it was due. That run never happened, and nothing said so. jiayang audit says it too.

Fixed:

  • jiayang webhook deliveries times each delivery by when its event came, the order it lists them in. It gave the last try’s time, so an older event tried again read as newer than the ones above it. One that took more than one try says how many.
  • jiayang webhook deliveries lists events in the order they happened, newest first, each with the time it happened. Events we picked up in the same minute came in any order, all with the time we picked them up, up to a minute late. --json has each one’s event_at, and the dashboard’s list uses the same time.
  • jiayang webhook list, webhook add and webhook edit say “all events” for a webhook that gets every event, and how many for one that gets more than three. They printed every name on one line, all 158 for a webhook added without --event. --json still has every name. webhook edit says only what it changed, not the whole row after it.
  • Signed in to staging, the CLI’s links and examples are staging’s. webhook add, audit-stream add, log-drain add, a redirect jiayang curl explains, jiayang uninstall and jiayang mcp install pointed at production’s docs, and the preview a viewer is asked for was on production’s apps domain. The docs are on the site of the API in use, and the preview’s example on the apps domain that API names.
  • jiayang curl --help and the docs say it exits 0 whatever the app answers, a 404 or a 502 included, as curl does, and that --fail exits 22 on a 4xx or 5xx.
  • jiayang audit and jiayang watch name a preview reached through the apps domain, as jiayang curl --preview reaches one, as they name one opened at its own address: on a preview of hello (p-0a1b2c3d), with the path the preview saw. It read as a request to the live app, with the apps domain’s path.

Added:

  • jiayang curl <workspace>/<app> --preview <version> sends the request to one of the app’s previews, as you, through the apps domain. It also takes the preview’s address, for someone the app is shared with who can’t list its versions. jiayang open --preview <version> prints the preview’s address. The MCP server’s call_app takes preview, as a number or a string. The agent plugin’s preview skill uses it, so update the CLI before the plugin.

Changed:

  • A container deploy and jiayang dev --docker give the image they build a name of their own, and remove it by that name once they’re done. They removed it by its id, which deletes the image whatever single name it has by then: two deploys of the same code at once could delete the image the other was about to save, or one you had named since the build began. Docker now keeps an image for as long as anything else names it.
  • jiayang deploy refuses --port, --instance-type and --instances for a Worker or a static site, before anything is built or uploaded. It deployed without them and said nothing. --dry-run refuses them too, and so does the MCP server’s deploy_app, by its own names for them.
  • jiayang deploy refuses --main and --compatibility-date for a container or a static site the same way. It dropped them without a word too.
  • When --kind was given, a flag for another kind says to change --kind, not to add it. Adding a second one failed.
  • jiayang detect, --dry-run and the start of a deploy print size: and containers: after port: when jiayang.json sets container.instance_type or container.instances.
  • --dry-run and the start of a deploy give the port, size and count that --port, --instance-type and --instances set over jiayang.json’s. They gave the file’s, which the deploy didn’t use.
  • The MCP server’s deploy_app schema gives instances as 1 to 20, the numbers it takes. It said 0 to 65535.
  • jiayang scale says so on a line of its own when the platform rolled the live version out again because the last deploy didn’t finish. Otherwise a scale rolls nothing out, with any CLI: the containers running keep running, even after an earlier push failed.
  • jiayang scale --help says what a scale changes: nothing rolls out unless the last deploy didn’t finish, and containers past the new number stop within a few minutes.
  • --help splits the sentences it joined with a semicolon.
  • What jiayang mcp’s tools change is in the audit log as via: mcp, not cli. A jiayang command an agent runs in a shell is still cli. The server says so in its User-Agent, jiayang/<version> mcp, which marks the entry and proves nothing. jiayang watch shows it as (mcp).
  • jiayang deploy --dry-run shows the entry and the compatibility date that --main and --compatibility-date set. jiayang detect and the dry run print main: and compatibility date: lines for a Worker when something sets them.
  • A kind from jiayang.json reads because jiayang.json says it's a container, where it said you said. With a kind given, the first line still names the framework detection found.
  • jiayang import --env-file reads a quoted value over more than one line whole, and leaves it out as Not set. It stopped at the second line, or read it as a variable of its own.
  • jiayang import says The directory <dir> already has files in it rather than starting with the directory’s name, which was given a capital. A dry run says why it stops there too.
  • jiayang kv put and jiayang kv rm say a change can take a minute or so to show everywhere. kv rm said the key was gone while kv get still read it.
  • jiayang mcp install cursor names a Homebrew install by its opt path, which lasts through brew upgrade, not the version’s own Cellar path.
  • jiayang dev --as webhook gives a delivery id and a signed time only for Stripe, Slack and Standard Webhooks, as the platform does. GitHub, Shopify and HMAC-SHA256 deliveries had both.
  • The MCP server: list_cli_sessions gives times as RFC 3339, workspace_insights takes hour, day, week and month for its window, query_database names run_sql for a write, delete_kv_key and set_kv_value say a change takes a minute or so to show, a missing key names list_kv_keys, and a directory outside the session’s says what to do for an upload, an import or a clone. A folder the client names as the plugin’s is never deployed from, whichever root reaches it.
  • jiayang env set and env remove on a container app, and the MCP server’s set_env, say the container takes about five minutes to restart with the change. They said a minute or two, and it took five and a half on production every time.

Fixed:

  • jiayang curl printed 200 OK for a stream cut off because your access to the app ended. It now says the answer was cut off and exits with code 1. Only a request sent as you is checked this way: one sent with a bypass token, and any other HTTP client, can still see a stream the platform cut as one that finished.
  • jiayang curl told someone refused with a 404 to run jiayang app list on the app’s workspace, whether or not they were in it. Someone outside it is pointed at jiayang app list --shared instead.
  • jiayang deploy of a container app whose build took more than about 15 minutes failed with “the push token was refused”, since the token was made before the build. It now asks for a new one when the build has left less than 10 minutes of it, and once more if the registry refuses it partway through the push.
  • jiayang deploy refuses an image whose programs are all for another architecture, as from a FROM --platform=linux/arm64 line, before it’s pushed. BuildKit marks such an image as built for linux/amd64, so it went live and couldn’t run.
  • jiayang dockerfile and the MCP server’s generate_dockerfile say a directory that deploys as a Worker or a static site isn’t a container app. They planned every directory as a container, so a Worker was told to write a Dockerfile, and a package.json Worker got a Node Dockerfile no deploy would use. Both take a kind (--kind, kind) to plan one as a container anyway.
  • A Bun project whose entry calls Bun.serve, with no start script, is detected as a container that runs on Bun. Its TypeScript entry made it a Worker, which Cloudflare refused with “Bun is not defined”. A typed call like Bun.serve<{ user: string }>(...) counts too. A Worker with a Bun server beside it for local work, in a file package.json doesn’t name, stays a Worker.
  • An image jiayang deploy refuses before the push, for a key no deploy may carry, is sent to the platform to be kept. It’s listed by jiayang scans, and the audit log, webhooks and Slack have an app.deploy_blocked for it, as for any refused deploy. The deploy prints Scan: refused and the scan’s id, as a Worker’s does. Nothing kept or logged the refusal.
  • The MCP server’s set_env refuses an argument it doesn’t take, like values or env, and names it and the ones it takes. It dropped them and said only that there was nothing to set.

Added:

  • jiayang deploy --instances <n> runs a container app on that many containers, each request going to one of them. jiayang.json takes it as container.instances. jiayang scale <workspace>/<app> <n> changes the number without a deploy, and jiayang app show gives it. The MCP server’s deploy takes instances.
  • jiayang workspace show says how many containers an app may run on the plan, and the container units its container apps share.
  • jiayang workspace create --region eu makes a workspace that keeps its apps’ databases, files, containers and archived audit log in the EU, where we offer it. The EU isn’t open on jiayang.cloud yet, so for now it’s refused. It can’t change later, and apps in an EU workspace need Enterprise. If the platform made it somewhere else, the command says so and fails. jiayang workspace show says where a workspace keeps its data, and the MCP server’s create_workspace takes region.

Changed:

  • jiayang app show prints a containers: line for a container app, between driver: and visibility:.
  • jiayang workspace show prints a data kept in: line after plan:, and containers per app: and container units: lines with the plan’s limits.
  • jiayang audit describes a change to how many containers an app runs as now runs 3 containers.
  • When jiayang.json or a flag names a size or a number of containers, jiayang deploy of a container app checks the workspace’s container units before it builds, and stops there when they’re spent, rather than after the push.
  • container.instances in jiayang.json stops CLI 0.1.11 and older with an error that starts jiayang.json isn't valid: unknown field `instances` . Upgrade every CLI that deploys the app before adding it, the GitHub deploy action’s cli-version included.
  • A container refusal past what Business runs now says to write to sales@jiayang.cloud. CLI 0.1.11 and older add “Upgrade the workspace at” and the Billing link after it, which a Business workspace can’t do itself: an Enterprise contract is the way past Business.

Added:

  • jiayang preview end <workspace>/<app> --pull-request <n> ends the preview a pull request’s GitHub run put up. The deploy action runs it when the pull request closes, with the credential its run traded for. The MCP server has it as end_preview.
  • jiayang deploy --preview with a pull request’s credential puts up that pull request’s preview, and says which pull request it’s for. jiayang versions and jiayang audit name the pull request beside its previews.
  • jiayang policy shows and sets a workspace’s publish policy: who besides its owners may open an app to the whole workspace or an email domain, share outside the workspace, open public paths, make bypass tokens, mint agent credentials and connect AI clients. jiayang policy breaches lists what was done before a rule by someone it doesn’t name, and jiayang policy end ends it. The MCP server has publish_policy, which only reads.
  • Every deploy is scanned before it goes live, for keys left in what it sends and for packages with published vulnerabilities. jiayang deploy sends the packages its lock files pin (names and versions only) and the project’s .jiayang-allow, reads a container image’s layers and config for keys before it pushes, and prints what the scan found under the app’s address.
  • jiayang scans <workspace>/<app> lists an app’s scans, refused deploys among them, and --version <n> or --id <id> prints one whole. jiayang versions marks a version whose scan found something, and jiayang audit says what each scan found.
  • jiayang workspace scan-policy <workspace> shows whether deploys with findings warn or are refused, and --secrets block or --vulnerabilities block turns refusing on. Turning it off is done in the dashboard.
  • The MCP server has deploy_scans, and a deploy’s answer says what its scan found and what to do about it.
  • jiayang log-drain sends an app’s logs, or every app’s in a workspace, to an HTTPS endpoint as signed JSON lines, Datadog, Grafana Loki or an S3-compatible bucket. test sends a test line, failed and retry list and send again the batches that failed for a day, and pause, resume, level and remove change one. The MCP server has list_log_drains and set_log_drain, which pauses, resumes or changes the level of a drain but never adds one.
  • jiayang insights <workspace> shows who opens a workspace’s apps: people, opens and when each app was last opened, the apps nobody opened in 30, 60 or 90 days, and apps whose owners have all left. --app narrows it to one app, --days picks 7, 30, 90 or 365, and --csv apps or --csv people prints a CSV. The MCP server has it as usage_insights, which only reads.
  • "kv": true and "queue": {"path": "/jobs/queue"} in jiayang.json give an app on Team or Business a key-value store and a queue of its own, made by the next deploy and bound as KV and QUEUE. jiayang kv status, ls, get, put and rm reach its keys, and jiayang queue status and send its queue. The MCP server has app_stores, list_kv_keys, get_kv_value, set_kv_value, delete_kv_key and send_to_queue.
  • jiayang db query <workspace>/<app> "<statement>" runs one statement on an app’s database and prints a page of the rows as a table. It’s read only unless you add --write, takes --limit and --offset to page, and --csv prints up to 10,000 rows as CSV, or saves them with -o. The MCP server has query_database, which only reads, and list_files, which lists an app’s files.
  • The MCP server has a tool for nearly everything the CLI does. An agent can now share an app with a domain or a group, answer requests for access, look after groups, read members, custom roles, single sign-on and SCIM, read and test webhooks and audit log streams, set an app’s AI budget and outbound list, pause, start and run schedules, put a preview live, read and change an app’s files and database, export and restore a database, restore a deleted workspace, read storage and traffic, list connected AI clients and revoke an agent’s credential. Anything that deletes or replaces data takes what it changes named twice, and so does turning an app’s outbound list off. query_database runs only a statement that reads. No tool changes who signs in, adds a member or a role, changes a group that gives a role, or sends the workspace’s events somewhere new.
  • The MCP server’s show_workspace reads a workspace’s plan, limits and allowed email domains, list_cli_sessions lists your CLI sessions without where they signed in from, and generate_dockerfile shows the Dockerfile a container deploy would build with, writing nothing.
  • jiayang sso <workspace> --status and jiayang scim <workspace> --status show how a workspace signs in and whether its SCIM token works, for its owners. Changing either stays in the browser.
  • jiayang dev --as takes a persona as well as an email: owner, editor, viewer, agent, token, scheduler, webhook (with --provider and --pattern), outsider and nobody. Each gets the token the platform would mint for that kind of caller, so an app’s checks for agents, bypass tokens, scheduled jobs and webhooks run locally. An outsider gets the platform’s 404 and never reaches the app, and a webhook reaches only the path its pattern opens. The page at /.jiayang has a button for each.
  • jiayang dev --docker runs a container app in the image a deploy would build, published on 127.0.0.1 only. A project that is only a Dockerfile runs this way without the flag.
  • A build for Windows on Arm. The PowerShell install script and the npm package install it on an arm64 PC, which until now got the x86-64 build and ran it under emulation.
  • jiayang import brings a project over from Vercel, Netlify or Replit, or from any git repository, as a new app: jiayang import vercel:<project> acme/app, netlify:<site>, replit or the repository’s address. It reads the project’s settings and production variables with a token you paste, used for that import only and never saved, clones the code, writes a jiayang.json, makes the app, sets its variables and secrets, deploys it and adds its scheduled calls. It shows all of that and asks first, and names what can’t come along with what to do instead. --dry-run only shows it. The MCP server has it as import_app, which never takes a token or a key from the conversation.
  • jiayang postgres connects a Postgres database you already have, like Neon, Supabase or RDS, and gives it to apps, which query it through the platform and never hold its password. add, rotate, update, check, remove, grant, revoke, show and list. The URL or the password is read at a hidden prompt or from stdin, never from a flag. Team connects up to 3 and Business up to 10. The MCP server has list_postgres, check_postgres, grant_postgres, revoke_postgres, remove_postgres and app_postgres. Connecting a database and changing its password stay yours, at the prompt.
  • jiayang network lets an Enterprise workspace’s apps reach services inside the company’s network, through a connector you run there, and lists the fixed addresses its apps send from. add prints the command that runs a network’s connector, service add puts a host and its ports on it, and grant and revoke choose which apps reach it.
  • jiayang ai key set takes keys for Google Gemini, Mistral, Groq, Cohere, Azure OpenAI (with --endpoint) and Amazon Bedrock (with --region), beside Anthropic and OpenAI. jiayang env set refuses a Groq or Bedrock key as a plain variable, as it does the others.
  • JIAYANG_DEBUG=1 prints the connection’s own error when a request gets no answer, for support.

Changed:

  • jiayang dev sets JIAYANG_DEV=1 for the app it runs. The SDKs from 0.3.0 take its http issuer only with it, and the platform never sets it.
  • --role is now only for an email, an agent or a token. --as viewer replaces --as you@example.com --role viewer, which still works.
  • The /.jiayang page and the outsider’s page can’t be framed by another site.
  • An app that takes the connection and closes it without answering, as a container does while it starts, gets a 502 that says so rather than an empty reply.
  • jiayang dev --docker removes its container and image however it stops, an error included, and waits for the container to go before it removes the image.
  • A wrangler config that binds D1, KV or a queue under a name the platform doesn’t give is refused with everything else it asks for, in one message, rather than on its own.
  • jiayang app delete warns by the terms the app’s owners agreed to. A deleted app is kept for 30 days only when you and every owner of the app and its workspace have accepted the 5 October terms, or from 4 November, and is otherwise deleted for good as before. A delete you were told is kept goes through with --kept, and nothing is deleted if that no longer holds. With Recently deleted full, it says only --for-good goes through. If it can’t read the app, it says so rather than warning that the delete is final, and an app that isn’t there is said to be missing.
  • jiayang app delete --for-good deletes an app already in Recently deleted, and a deleted app says it can be deleted for good too. jiayang workspace delete --for-good opens the page that deletes a deleted workspace for good. The MCP server’s delete_app takes for_good and kept.
  • A first deploy that fails takes back the app it made, by its id, and deletes it for good, so the same deploy can run again. If the app changed in between, it’s left as it is and the deploy says why.
  • jiayang deploy to an app that was deleted says so and until when it can be restored, rather than offering --create. A deploy cut off by its workspace being deleted says it isn’t live, and what to delete after a restore. A directory given before the app is told the app goes first.
  • jiayang workspace members marks who waits for the identity provider after a restore, and jiayang whoami says where you’re held. jiayang audit says when someone held was let back in.
  • jiayang db restore that may have run says the bookmark that undoes it. When the platform won’t say where a restore goes, having been asked too often that hour, it asks as it used to rather than saying only to wait, since --yes still restores.
  • jiayang files rm, get and put keep a leading ./ in a file’s name: rm ./secret deleted secret. get and put refuse it, as any dot part. jiayang files get --out writes into a device or a pipe as it is, so /dev/null and /dev/stdout work.
  • A request that gets no answer says plainly why: a proxy that refused it, nothing listening (on Windows too), or a request that couldn’t be made at all, which isn’t tried again.
  • The line naming a request for support goes under a message of more than one line, not after it.
  • The dashboard opens in a browser only for someone at a terminal, never under --json or in a script.
  • jiayang app list says 1 person for one person outside the workspace, not 1 people. jiayang access on an app shared with nobody says so and who can still open it, where it printed nothing.
  • The MCP server asks again before set_outbound_list turns an app’s list off, marks export_database as one to ask about, since the database pauses while it runs, and names its own tools for the CLI’s commands in limits and refusals.

Added:

  • jiayang billing show <workspace> prints the plan, what it costs, when it renews and this month’s requests against the allowance. On Enterprise it prints the contract’s terms and the invoices Stripe sent, each with a link to pay it. jiayang billing open opens the Billing tab, since paying and changing the plan stay in the browser. The MCP server has the same as billing_status, which only reads.
  • jiayang sessions list and jiayang sessions revoke <id> list and end your CLI sessions. jiayang logout --everywhere ends every one of them, this one too, and disconnects every AI client you connected. Bypass tokens and agent credentials you made keep working after you sign out: add --tokens to revoke them too.
  • jiayang connections list and jiayang connections disconnect list and disconnect the AI clients connected to apps as you, or to an app you manage.
  • jiayang agent rename renames an agent. The MCP server has it as rename_agent.
  • jiayang webhook edit changes which events a webhook or Slack channel gets, or turns it on or off.
  • jiayang egress usage <workspace>/<app> shows the hosts an app sent requests to over the last 30 days, with what its list refused. The MCP server has it as outbound_usage.
  • jiayang sso, jiayang scim and jiayang workspace export open the dashboard’s page for each. A CLI session can’t change who signs in to a workspace or carry it off.
  • jiayang app deleted and jiayang app restore list and restore the apps a workspace keeps for 30 days after they’re deleted, where the platform keeps deleted apps. jiayang workspace deleted and jiayang workspace restore do the same for workspaces. The MCP server has list_deleted_apps and restore_app.
  • jiayang db restore --to puts an app’s database back as it was at a moment in the last 30 days, and prints a bookmark that undoes it.
  • jiayang role makes, changes and deletes a workspace’s custom roles, and gives them to members or groups. jiayang workspace add --custom-role gives one as the member joins.
  • jiayang audit-stream sends a workspace’s audit log to Splunk, Datadog, an HTTPS collector or an S3-compatible bucket, and retries failed batches. The MCP server has list_audit_streams, which only reads.

Changed:

  • jiayang app list shows owners and admins, under each app, who can open it, what it sends requests to, who made it and when it was last opened.
  • jiayang workspace show and jiayang workspace usage know Enterprise: what its plan allows, and its usage against what the contract includes each calendar month.
  • jiayang app delete says whether the app can be restored and until when. --for-good skips the 30 days.
  • jiayang deploy takes a worker or container section in jiayang.json as the kind it names, and stops on a section for another kind than the one deployed, which it used to drop without a word. An index.html beside a Worker’s entry is no longer taken for a static site: the deploy asks which you meant.
  • The rewrite printed for an old flat jiayang.json keeps its kind. Without it, a Worker with an index.html went up as a static site serving its own code.
  • A static site never uploads jiayang.json or a wrangler config from its top, and stops on TypeScript source, which a site would only serve for anyone to read.
  • A failure on our side names its request, for support to find it.
  • jiayang curl takes the file the MCP server’s create_bypass_token writes as it is, in --token or JIAYANG_TOKEN: its # lines are skipped. Anything else that isn’t one token is said plainly, not as builder error: failed to parse header value.
  • jiayang schedule list says when a schedule last ran late, and how many runs that one stood in for.
  • jiayang rollback to a preview says the version is live, not live again. So does the MCP server’s rollback, which said the app was back on it.
  • jiayang secret set refuses a host no app’s request reaches, ours or one under .internal, .local or .localhost, before it asks for the value.
  • jiayang db export --out - writes to stdout, not to a file named -.
  • jiayang files get downloads a file whose name has a space or a % in it, which it could list but not fetch. A file that isn’t there is no_such_file, not a missing app, a static site says it keeps no files, and --out - writes to stdout.
  • jiayang files put names the value that can’t be a file’s name, and says so when its two names are the wrong way round.
  • jiayang workspace domains <workspace> with no list shows the domains set now.
  • jiayang app list with no workspace lists the apps of the only one you’re in.
  • jiayang whoami and jiayang workspace show say when Free’s apps are paused because we can’t count their usage for a while, and that it’s ours to fix.
  • jiayang audit and the audit CSV mark what the identity provider did over SCIM, as the dashboard does.
  • jiayang ai key remove asks first, and takes --yes where there’s no terminal to ask at. AI budgets are printed with their thousands grouped.
  • jiayang deploy finds a Worker in worker.js, worker.mjs and their src/ copies, and in the main or module package.json names when that file has a default export.
  • jiayang mcp install cursor from npm says the command it wrote is npm’s own copy, which runs without Node and stays put through updates. From npx, pnpm dlx or bunx it stops, since their cache is cleared.
  • Every failure under --json is JSON with a code: a command line the CLI can’t read is invalid_argument, and one that had none is failed, not null.
  • Prose is wrapped to 80 columns at a terminal. Piped or saved, it’s as before.
  • jiayang app public-paths prints, under each path, the address to send its requests to. The app’s own address asks everyone to sign in, public paths included, so a 401 there read as the path not being open. The MCP server’s list_public_paths has it as url.
  • jiayang token list says when each token ends, or ended.
  • jiayang deploy of an app that isn’t there, by someone whose role can’t make apps, says a workspace owner or admin has to make it. It offered --create, which was then refused.
  • jiayang webhook list says why a webhook is off, and when one that’s still on is failing.
  • jiayang audit names the webhook a webhook entry is about and a database restore’s undo bookmark, and names an agent’s request by the name it had when it made it.
  • jiayang curl prints only the error when an answer stops short, or a stream stops because your session ended, in place of the status. It printed 200 OK first, over an error and an exit code of 1.
  • jiayang promote of a version that failed keeps Cloudflare’s reason on one line, and the message ends with a full stop.
  • jiayang schedule off on a schedule that’s already off, and on on one that’s already on, say so and change nothing. One we turned off says why and that it has to be added again.
  • jiayang webhook test exits with 1 when the test event wasn’t delivered.
  • jiayang webhook add --name and jiayang webhook rename refuse a name another webhook or Slack channel in the workspace already has, in any case.
  • jiayang workspace usage sizes its table the way its storage line, the plans and the dashboard do, in units of 1,024, so the same files no longer read 1.2 GB in one and 1.3 GB in the other. A database or files not measured yet say not measured, not 0 B.
  • --help ends every help text of more than one sentence with a full stop.
  • jiayang deploy to a name that can’t be one quotes it as you typed it. A name of lowercase letters alone came back with a capital.
  • jiayang share <app> @resend.dev is refused: nobody has an inbox at a mail testing service’s domain, and a share with it reached every test account.

Added:

  • jiayang webhook add --name gives a webhook or Slack channel a name, like “deploys to ops”, so you can tell apart several that go to the same site. jiayang webhook rename names one later, or takes its name off, and jiayang webhook list shows the name beside its address.
  • jiayang workspace usage shows what the workspace stores against its plan, split into site files, databases and app files, and each app’s files in the table. When the workspace is over, it says what that stops and how to make room.
  • jiayang ai grant and jiayang ai show say when an app’s list of hosts is on and leaves out the provider’s, so its requests to Anthropic or OpenAI would be refused, and give the jiayang egress allow command that fixes it.
  • jiayang audit and jiayang watch mark a request made to a preview, with the preview’s name, like p-0a1b2c3d. Before, only the host in --json told it apart from the live app.
  • jiayang access <app> ends with viewer everyone in acme when everyone in the workspace can open the app, and --json has visibility. It listed only the people it was shared with.

Changed:

  • jiayang group delete needs --yes. Deleting a group takes away every app’s share with it, and the only way back is to make the group again and share each app again. Group messages call a group “the ops group” throughout.
  • jiayang deploy of a static site checks its _headers and _redirects before uploading anything. A rule the platform would refuse stopped the deploy only after the changed files had gone up and counted toward your storage.
  • jiayang promote of a version that failed says it didn’t deploy and why. It said to run jiayang rollback, which then refused it. A version that’s already live, or still going up, says so too.
  • jiayang deploy to a workspace or app name that can’t be one, like acme/My_App, stops straight away and says what a name can hold, before looking at your project. Yun looks sad only when the platform turns a deploy down, not over a typo or something that isn’t there.
  • jiayang files rm of a name the app doesn’t have says nothing was deleted, rather than “Deleted”. jiayang files ls says its times are UTC.
  • jiayang webhook test on a Slack channel that Slack answered 404, 410 or 403 says what that means in Slack: the webhook or its channel is gone, the channel is archived, or Slack won’t let it post there.
  • Sharing an app you can’t see says there’s no such app you can see and how to list the ones you can. It said only the app’s owners and admins could share it. Unsharing someone the app isn’t shared with no longer starts “not found:”, and points to jiayang access <app>.
  • jiayang schedule add and the MCP server’s add_schedule with a shortcut like @daily say shortcuts aren’t read and give the five fields to write instead. They said the schedule had one field.
  • The MCP server’s rollback, used to put a preview live, says the app is now on that version, not back on it: a preview was never live.
  • jiayang agent create says what to run next with the agent’s name, as the other agent commands do, rather than its id.
  • jiayang deploy --preview says a preview answers until the app’s next preview, whoever puts it up, not until “your” next one.
  • --help fits an 80-column terminal. Each paragraph was one line, up to 241 columns, which the terminal broke again mid-word.
  • jiayang schedule on for a schedule we turned off, because whoever added it can no longer edit the app or for single sign-on, says to add it again. It said the schedule would run, and the platform turned it off again a minute later.
  • jiayang audit says whether a schedule was turned on or off.
  • jiayang audit names the agent an app was granted to, or a credential was minted for or revoked from, as release-bot (ag_…), the way it names an agent it made or ended.
  • jiayang audit says the role a member or a grant had before a change, as bo@example.com as admin, was owner, and which limit a plan.limit entry hit, as audit_export, not on free.
  • jiayang group add says when the person is already in the group, rather than that it added them, and names the group as “the finance group”.
  • jiayang deploy of an app that isn’t there, without --create, gives the command with --create that makes it.
  • jiayang curl writes the body out as it arrives, so an event stream shows each event as it’s sent. An answer that stops short, or a stream that stops because your session ended, is an error that says so. It printed 200 OK and exited 0.

Added:

  • jiayang share <app> @acme.com shares an app with everyone whose address is exactly at that domain, as viewers. You can share only the domain your own address is at, and never a free mail provider’s or a public suffix.
  • jiayang share <app> --group <name> shares an app with one of the workspace’s groups, as viewers. jiayang group creates, lists and deletes groups and adds and removes their people, who needn’t be in the workspace.
  • jiayang unshare takes @<domain> and --group the same way. When someone you unshare can still open the app through their domain, a group or the whole workspace, it says which.
  • jiayang access <app> lists the domains and groups an app is shared with, after the people.
  • jiayang workspace remove says which apps the person’s domain still lets them open.
  • jiayang mcp’s app_status shows the domains and groups an app is shared with, and set_access names what still lets someone in after their access is removed.
  • jiayang domain add, list and remove give an app a custom domain, like app.example.com. add prints the records to add at your DNS provider: a CNAME that points the name at us, and a TXT record that proves it’s yours. The domain works once we’ve seen both and its certificate is issued. The MCP server has the same as add_domain, list_domains and remove_domain.
  • jiayang agent create|list|grant|revoke|token|end: agents are callers of a workspace’s own, each reaching only the apps granted to it with jya_ credentials of its own, and named as itself in the audit log. --json on each.
  • The MCP server has list_agents, create_agent, set_agent_access and end_agent. None of them mints a credential, so a secret never passes through an agent’s conversation.
  • jiayang audit, watch and top name an agent as agent:<id>.
  • jiayang egress list|allow|deny|on|off <workspace>/<app> holds an app to a list of hosts it may send requests to. allow takes a host like api.stripe.com or a pattern like "*.stripe.com". Only workspace owners and admins can add a host or turn the list off.
  • jiayang ai shares the workspace’s Anthropic or OpenAI key with apps, each up to a monthly budget: jiayang ai key set <workspace> anthropic stores it (pasted at a hidden prompt or piped in), jiayang ai grant <workspace>/<app> anthropic --budget 25 lets an app use it, and jiayang ai keys, show and revoke list, show and take it away.
  • jiayang webhook add|list|remove|test sends a workspace’s events to a URL of yours, signed in the Jiayang-Signature header, or with --slack to a Slack channel, whose URL you paste at the prompt or pipe in so it stays out of your shell history. add shows the signing secret once, and test sends a test event now and says how it went. For owners and admins.
  • jiayang deploy --preview puts a Worker app or a static site up at a preview address of its own, p-<eight characters>--<app>, and leaves the live version as it is. Only people the app is shared with can open it, for 7 days or until the next preview. jiayang versions shows each preview’s address and whether it still answers.
  • jiayang promote <app> <version> puts a preview live, as it is.
  • jiayang schedule add|list|remove|run calls a path on an app on a schedule, as five cron fields in UTC. Each run is signed as the scheduler: kind service, with a sub that starts with scheduler:.
  • jiayang schedule on and off turn a schedule on and off. One we turned off because its maker can no longer edit the app, or for single sign-on, is added again instead.
  • The MCP server’s deploy_app takes preview: true, and list_schedules, add_schedule and remove_schedule manage an app’s schedules.
  • jiayang files ls|get|put|rm <workspace>/<app> lists, downloads, uploads and deletes the files an app keeps, where the platform has storage on. Owners can do all four, admins can list and delete. get saves under the file’s own name, or --out, or --stdout, and won’t replace a file that’s already there unless you pass --force. put takes up to 25 MB, and - reads stdin. For get and put, a name with anything that would need encoding is refused before anything is sent. rm takes any name the app wrote, spaces and all, so you can always make room. Only a name with a . or .. part can’t be deleted this way. ls shows control characters and anything else outside plain ASCII in a name escaped, so a name an app wrote can’t act on your terminal.
  • jiayang deploy takes a deploy credential from JIAYANG_DEPLOY_TOKEN and uses it in place of a login. A GitHub Actions run gets one by trading its OIDC token, which the deploy action in actions/deploy does for you, so nothing is stored in the repository. The credential deploys the one app it was made for and nothing else, so --create isn’t taken with it. Nothing the CLI starts (your build, wrangler, docker) gets JIAYANG_DEPLOY_TOKEN in its environment, so a build can’t bake it into the app. JIAYANG_DEPLOY_TOKEN_FILE names a file holding it instead, which the deploy reads and deletes before it starts anything, so the credential is in no process’s environment at all. The GitHub action hands it over that way. A file that doesn’t hold a deploy credential, or is a link, is left alone and the deploy stops.
  • jiayang versions names the GitHub Actions run that made a version, beside the person whose permissions it had.
  • jiayang app mcp <workspace>/<app> on lets AI clients such as Claude and Cursor connect to an app that is an MCP server. Each signs in as someone the app is shared with, who approves it in a browser, and reaches only that app, as them. off disconnects every one of them, from its next request, and turning it on again brings none back. jiayang app show says when AI clients can connect.
  • jiayang access <app> ends with how many people are waiting for access, when you can share the app and anyone is, and points to jiayang access <app> requests.
  • jiayang mcp install cursor puts JIAYANG_CONFIG_DIR in the server’s env when the config directory isn’t the default one, from the environment or --config-dir, and says which. Cursor doesn’t have your terminal’s environment, so the server it started read the default config’s session instead. That directory holds the platform you signed in to, so JIAYANG_API isn’t written.
  • Yun, our cloud, says hi over jiayang --help and a bare jiayang, after you sign in, after jiayang init writes a template and at an app’s first deploy. Yun naps when you sign out or nobody is signed in, and looks a little sad when the platform turns a deploy down. Yun goes to stderr, and only when stdout and stderr are both a terminal: never with --json, NO_COLOR or CI set. JIAYANG_NO_MASCOT=1 turns Yun off. The MCP server never draws Yun.

Changed:

  • jiayang deploy ends with “Version 3 (…) is live.” and the app’s address, rather than “Deployed version 3 (…).”. For an app that’s taken down it says the version is saved, but not served until the takedown is lifted.
  • jiayang share, jiayang access approve and the MCP server’s set_access say someone can now use the app “as a viewer” or “as an editor”, rather than “as viewer”.
  • jiayang deploy --dry-run ends with “That was a dry run, so nothing was deployed.”, and signing in with no workspace yet says to make one, a little shorter.
  • jiayang access <app> --json now answers {"grants": [...], "domains": [...], "groups": [...]} rather than a bare list of people, so the domains and groups an app is shared with show too. People are under grants, as before.
  • In jiayang audit --json, app.database_exec and app.database_exec_refused entries from 3 October 2026 on have a keyed hash of the statement in sha256, and say which key made it in hash, like "hmac-v1:k1". Before, sha256 was a plain SHA-256 of the statement, with no hash, so an old entry never matches a new one, and hashing a statement yourself won’t find it. Entries whose hash differs never match either.
  • A jiayang deploy whose connection drops before the platform answers looks for the new version, as it does for a deploy that takes too long, instead of failing with what the TLS library said.
  • A deploy that made its app and then failed deletes the app again only once the platform says none of its versions is live or on its way. When the deploy may have gone through, or nobody can tell, the app is kept and the error says so, with jiayang versions to see whether it went live. That error is one sentence for a deploy that timed out or that a gateway gave up on too. It said where to look twice, with the connection’s own error in between. A deploy that failed before it sent its version, uploading files or pushing an image, deletes the app straight away as before: nothing that could go live had left your computer.
  • A deploy whose connection drops stops looking for its version after 20 seconds when none has turned up, rather than 3 minutes: a drop can come before the deploy reached the platform.
  • A deploy that made its app no longer tries to delete it after a failure when the app is already gone, or out of your reach. The error said to delete an app that wasn’t there. One out of your reach is still there, and the error says so.
  • A version on its way live is looked at every second for its first 15 seconds, then every 5, so a deploy that goes live a moment after the platform answers says so a moment later.
  • jiayang rollback, jiayang env set and jiayang env remove whose connection drops, or that the platform doesn’t answer in time, say the change may have gone through and how to check, instead of what the TLS library said. So do the agent’s rollback and set_env.
  • jiayang access approve <app> <id> and deny <app> <id> for a request that’s already decided, or was never there, say so, or that there’s no open request with that id, and how to list the open ones (jiayang access requests <app>). They said the app wasn’t found and offered to create it. deny names the person it turned down, not the request’s id.
  • jiayang deploy --create that can’t delete the app it made after a failed deploy no longer puts a full stop after the platform’s reason when it already ends in one, a ?, a ! or an ellipsis, inside closing quotes or brackets or not. A reason ending in a colon gets a full stop in its place, one ending in a link is followed by a new line rather than running on into how to delete the app, and no reason at all leaves no stray stop.
  • jiayang deploy says “Deploying 1 file”, not “1 files”, and a workspace at a plan’s limit of one app “has 1 app”.
  • jiayang init names your workspace in the deploy command it ends with when you’re signed in and in only one. Otherwise it still says <workspace>.
  • jiayang audit --csv prints the oldest entry first, the same order as the dashboard’s download.
  • jiayang audit without --app, refused to an app’s owner, says to try --app with the app’s name: an owner can read the log of the apps they own. jiayang watch <workspace> says to watch <workspace>/<app>, and the MCP server’s audit_log says to pass app.
  • The static-site template from jiayang init has a 404.html. A path with no page gets it, with a 404 status, instead of the front page with a 200.
  • jiayang curl says so when a redirect came back with no Location. The gateway now drops every redirect that would leave the app’s own /<workspace>/<app>, to another site too, so a token never follows one onto another app. An app that hands a script a URL somewhere else, like a signed download link, returns it in the body instead.
  • Taking away something that isn’t there says what’s missing rather than that the app or the workspace is: sharing with a group that doesn’t exist, unsharing a group or a domain the app isn’t shared with, removing a custom domain, a schedule or an outbound host the app doesn’t have, adding to or removing from a group, revoking an agent’s credential that’s already revoked, and taking an app from an agent that never had it.
  • jiayang agent end asks before it ends an agent for good, and with no terminal to ask at needs --yes. The agent commands call an agent by its name, as you typed it, and say “credentials”, not “tokens”.
  • A viewer’s jiayang deploy, or --preview, says who can deploy the app before it detects anything. Granting an app to an agent without the role for it says who can.
  • jiayang deploy --json --preview puts the preview’s address in url and the live app’s in live_url, the way the MCP server’s deploy_app does.
  • jiayang promote of a preview pushed out of the newest 20 versions says it’s too old to promote.
  • jiayang audit names an agent and the credential it used, the scheduler by its schedule, and whose request for access was approved or turned down.
  • jiayang schedule list says off (maker_cannot_edit) for a schedule turned off because its maker can no longer edit the app, and off (sso_required) for one single sign-on turned off.
  • jiayang access requests keeps the line breaks in a note.
  • jiayang share <app> *.acme.com says it isn’t a domain, and jiayang share <app> acme.com says to put @ in front. Both said it wasn’t a valid email address. The usage line of share and unshare shows --group, and unshare says the address as the platform keeps it.
  • jiayang curl says a refusal came from Jiayang Cloud rather than “our edge”, and names your workspace in what to run next. jiayang webhook add --slack names it too, not <workspace>.
  • jiayang ai show says “1 request”, not “1 requests”.

Security:

  • With JIAYANG_DEPLOY_TOKEN set, jiayang deploy sends it to the API JIAYANG_API names, or to https://api.jiayang.cloud, never to the API this machine is signed in to.
  • Nothing the CLI starts gets ACTIONS_ID_TOKEN_REQUEST_TOKEN or ACTIONS_ID_TOKEN_REQUEST_URL, so a build’s dependencies can’t ask GitHub for a token of their own in a deploy job.
  • A deploy now stops on a file that holds one of our own tokens (a deploy credential, a bypass token, a session or a push token), not only a CLI session.

Upgrading:

  • On a network, or behind a proxy, that cuts a request after 5 seconds with nothing back, the platform now answers a deploy from 0.1.2 or later in time, and the CLI follows the rest. 0.1.0 and 0.1.1 still wait in the request for a first site to go live, so there they can lose the connection and delete the app they made a moment before. Upgrade if you’re on either.

Added:

  • jiayang uninstall takes the CLI off your computer. It revokes the bypass tokens your agent made here and deletes their secret files, ends the session, and deletes the config directory, leaving anything in it the CLI didn’t write. If the install script put jiayang there, it deletes the program and takes out the lines the script added to your shell’s startup files, and nothing else. For Homebrew, npm, cargo and Windows it prints what to run. It takes jiayang-cloud out of the project’s .cursor/mcp.json and says how to take it out of other agents. It asks first, or takes --yes. --keep-config keeps your settings. Your apps and workspaces aren’t touched.
  • jiayang init <template> [dir] starts an app from a template, ready to deploy: static-site, worker, internal-tool (a Worker with a database), express or fastapi. It writes into ./<template> unless you name a directory, never replaces a file that’s already there, and ends with the jiayang deploy command to run next. jiayang init on its own lists the templates.
  • jiayang mcp has list_templates and create_from_template, so an agent can go from a sentence to a deployed app. A template is written only where a deploy could read from, by the same rules as deploy_app, and never over a file. Neither needs anyone signed in.
  • jiayang access <app> requests lists the open requests for access to an app, with what each person wrote. jiayang access <app> approve <id> shares the app with them as a viewer and emails them its link. deny turns a request down without telling them.
  • jiayang audit --csv prints the log as CSV, with the same columns as the dashboard’s download. A cell that a spreadsheet would read as a formula is written so it reads as text.

Added:

  • jiayang mcp install cursor sets Cursor up for the project you run it in. It writes the project’s .cursor/mcp.json with this jiayang’s full path, so Cursor finds it even when it was opened from the Dock, which doesn’t have your terminal’s PATH. Running it again changes nothing. Other servers in the file are kept, and a file that isn’t valid JSON is left alone.

Changed:

  • Every error reads as a sentence. The CLI’s own words start with a capital, every message ends with a full stop, and a name at the start, like a workspace’s, is never capitalised.
  • jiayang deploy and jiayang detect no longer take from in a string, a comment or a regular expression for an import. A Worker with "comes from" in it was refused for a package called + that it never imported.
  • jiayang logs --version 3 finds version 3’s lines when version 4 wrote a lot in its first minutes, and refuses a version the app never had. A read with no lines says “in the last hour”, not “since 1h”, and how far back the plan lets you read, not how long it keeps lines: every plan’s lines are kept 7 days. A viewer is told once who can read the logs.
  • jiayang app show lists the paths anyone can reach without signing in, and which of them have no signature check. --json has them as public_paths.
  • jiayang audit puts (deleted) after a deleted app’s name on every entry about it, and jiayang watch does on requests too. An env removal reads removed, not unset, and an allowed request reads access allow, without (allowed).
  • jiayang curl says plainly that a 401 or 403 without our edge’s X-Jiayang-From header came from your app.
  • jiayang db export says “Exported the database of acme/notes to acme-notes.sql (48,213 bytes)”, with the size grouped by thousands.
  • jiayang workspace usage says storage over the limit in GB-months, the unit it’s priced in, rounded as the Billing tab rounds it. A meter we haven’t priced yet says that’s ours to fix, the usage limit rule is said once in plain words, and requests with no CPU measured say only their CPU time is free. A limit lowered partway through an hour is said to still count that hour against the higher one, and apps paused at the default $0 limit are said to have run out of the plan’s allowances, not its usage.
  • jiayang workspace usage on a subscription made at an older price says it keeps the prices it started with, usage prices included, until the workspace changes plan. It showed $199 with nothing to say why the pricing page says $215.
  • jiayang workspace usage --previous for a short time on Free before a plan began says when it was, to the minute, instead of calling it last month. An empty table says no app used anything, not that the workspace has no apps.
  • --driver takes worker and container as well, and its help says which kinds each runs.
  • jiayang detect calls a JavaScript monorepo’s root that, not a workspace.

Agents:

  • Refusals read as sentences, with a capital and a full stop, and never capitalise a workspace’s name.
  • set_visibility says who can reach the app, as the CLI does.
  • call_app, send_to_app and set_env take headers and variables as an object of names and values too, and any other shape is refused with both shapes shown.
  • app_logs refuses a version the app never had, finds a version’s lines behind the next one’s, and says when a short page has older lines to read on to. Someone who can’t read the logs is told who can, as jiayang logs says it, not the platform’s “You don’t have permission to do that.”
  • app_status lists the paths anyone can reach without signing in.
  • call_app says a 401 or 403 without our edge’s mark came from the app.
  • workspace_usage says storage in GB-months and names a short time on Free before a plan as that. It says a subscription made at an older price keeps it, and words the usage limit as the CLI does.

Changed:

  • After a deploy or rollback that replaces a live Worker version, jiayang says the old version may answer some requests for a minute or two, not up to a minute. env set and env remove say the same of when the live code sees the change.
  • jiayang logs labels each line with the version that wrote it, not the one that was live, so --version shows the lines that version wrote. A line we can’t tell, such as a container’s own output, still gets the version that was live when it was written.
  • jiayang app list on an empty workspace tells an owner or admin it has no apps yet, and tells a member there may be apps not shared with them.
  • jiayang rollback to a version the app doesn’t have says the app has no such version, and points at jiayang versions.
  • jiayang workspace usage shows the default usage limit as $0 a month, as the dashboard does, and says whether usage before the billing month began in its first hour was on Free, and so on no invoice, or on the last month’s invoice.

Agents:

  • rollback, deploy_app and set_env say a replaced version may answer for a minute or two.
  • app_logs gives each line the version that wrote it, and its version filter means lines that version wrote.
  • rollback to a missing version says the app has no such version.
  • workspace_usage says the default usage limit is $0 a month, and whether usage in the billing month’s first hour was on Free or on the last month’s invoice.

Changed:

  • A container deploy removes the image it built from Docker however it ends: pushed, failed, or stopped with Ctrl-C. It says when the image is up and it’s waiting for the platform.
  • Ctrl-C before a deploy’s version is sent says nothing was deployed, deletes an app --create made for it, and exits 130.
  • jiayang detect, jiayang dockerfile and deploy --dry-run no longer say a container has a Dockerfile when it has none. The dry run refuses what the deploy would, and detect exits 1 and gives the reason in --json as problem.
  • jiayang --json logs lists lines oldest first, like the text. --follow looks back a minute, since Cloudflare can take half of one to make a line readable.
  • Not being logged in has a --json code: not_logged_in.
  • jiayang secret set checks the name, --host, --header and --format before it asks for the value, and names the flag that’s wrong. It tells a header that isn’t one from one that can’t carry a secret, suggests the hostname for a host with a port, and gives these errors the --json code invalid_argument.
  • jiayang rollback to the version already live says so.
  • jiayang token list and jiayang app list line up their columns, a small site’s size is <1 KiB, and jiayang unshare says plainly when the app isn’t shared with someone.
  • An app the platform took down says so in app show, app list, deploy and env set: a deploy is kept but not served until it’s lifted. A deploy says why once, before it builds.
  • jiayang token revoke and jiayang app delete delete the files the MCP’s create_bypass_token wrote the tokens’ secrets to, as the MCP’s own tools do. Only files for the platform you’re signed in to go.
  • A workspace member at the plan’s app limit is told to ask an owner or admin, with no billing link, as the platform now tells them.
  • An app that isn’t found says it may not be shared with you, and offers --create only when no app has the name.
  • jiayang audit --app finds a name’s deleted apps too, and marks them (deleted).
  • jiayang workspace usage shows what a plan switch holds apart from the old plan, and --previous on a workspace made after that period says it has nothing to show.

Agents:

  • revoke_bypass_token and delete_app delete the files create_bypass_token wrote the tokens’ secrets to. create_bypass_token writes no file for an id that isn’t a token id, and revokes that token.
  • A missing app points at deploy_app with create_if_missing, list_apps and whoami, and delete_app on one says it may be deleted already. set_access says once that someone has to join the workspace, and call_app answers every platform 404 as an error.
  • A refusal starts with a capital, and one a member can’t act on says to tell the person rather than offer an upgrade.

Security:

  • Names can’t hide characters any more. jiayang refuses bidi controls, zero-width and every other invisible character in workspace, app and token names, and prints any stored before without them. A zero-width joiner stays only where it changes what shows, as in an emoji or a script that joins its letters, so one name can’t pass for another. The England, Scotland and Wales flags are allowed. jiayang audit and jiayang watch strip control and bidi characters from what they print.
  • An email address with a hidden character in it is shown with that character escaped, like ceo\u{200b}@acme.com, wherever the CLI and the MCP tools print one, so it can’t pass for another address.
  • A bypass token given to jiayang curl goes only to the apps of the platform JIAYANG_API names, or the one you’re signed in to. Before, with no login it went to production’s apps whatever JIAYANG_API said. When the CLI doesn’t know where that platform’s apps are, it doesn’t send the token and says to set --apps-url.
  • An app that isn’t shared with you answers 404, the same as no app, so a refusal no longer tells you it exists.
  • jiayang audit and jiayang watch show a refused or unknown bearer token as an unknown token, never as the platform.
  • jiayang curl refuses gateway paths that aren’t UTF-8, and NUL.

New:

  • jiayang workspace usage shows this period’s requests, CPU time, database rows and storage, what they cost past the plan, and where Free stops. --previous shows the last period. The MCP server has the same as the read-only workspace_usage tool.
  • jiayang workspace usage says your plan and what it costs a month, and when a switch to another plan is still going through. Apps deleted in the period stay in its table, marked (deleted). When a period began partway through an hour, it says why the apps can add up to more than the meters.
  • jiayang workspace usage and jiayang whoami say when a Free workspace’s apps are paused for the month.
  • jiayang logs leaves the platform’s own lines out unless you pass --platform, and reads a container’s log levels.
  • jiayang watch names the app on each line.
  • jiayang login says what to do when the sign-in page emails you a code and it doesn’t come: check spam, ask for a new one, then write to support@jiayang.cloud.
  • When the platform refuses you an app in a workspace you own or run, jiayang curl and call_app say the app is there and give the jiayang share command that lets you in.
  • Deploys: bun and deno apps, VitePress sites built from the root their script builds, uv and poetry apps run from where their packages went, and chained start commands. A deploy that can’t build or start is refused before it uploads, and a failed docker build shows the step’s output.

Changed:

  • A deploy follows its version until it’s live and says which version it replaced. If Ctrl-C stops the wait, it says whether the version went live, failed or is still going. deploy_app now says too that the old version can answer for a moment longer.
  • A container deploy removes the image it built from Docker once it’s pushed. A failed push leaves it.
  • Python images install packages before copying your code, so an edit no longer reinstalls everything and pushes every layer again. A requirements.txt that installs local wheels, or uses --find-links or --no-index, builds.
  • jiayang audit names deleted apps on every entry, and --app takes a deleted app’s name. It names the recipient, the statement and the rollback, says whose version the platform put back and which, and what a refused removal would have taken.
  • jiayang watch --denies and jiayang top ask the platform for refusals alone, so a busy workspace’s refusals no longer go missing. Neither skips entries that reached the log together.
  • jiayang watch --tail N counts only the lines it prints, and --tail 0 prints none.
  • jiayang curl starts the status on its own line when stdout and stderr share a pipe, on Windows too.
  • A refusal from the platform says so, with its cause. A 502 after dispatch no longer blames the app. A 404 says the app may not be shared with you, and who to ask.
  • jiayang env set on a static site says the change comes with its next deploy.
  • A deploy refused for the plan’s app count suggests an upgrade only to a plan with room.
  • create_bypass_token takes any token name the platform takes, such as Café ci.
  • jiayang token list says a token opens nothing once its maker no longer has an account.
  • The audit log’s archive paging is followed in jiayang audit and the MCP tools.

Security:

  • jiayang curl and the MCP tools call_app and send_to_app refuse any path that climbs out of the app they name (.., %2e%2e, ..%2f and the other spellings). Before, one app’s path could reach another app you can open.
  • jiayang mcp refuses to deploy from a hidden directory anywhere in the path, the project root included.

New:

  • jiayang logs, and the app_logs tool, read an app’s recent output.
  • jiayang db exec runs one statement on an app’s database.
  • jiayang app list --shared lists apps people have shared with you. list_apps includes them.
  • Container redeploys roll out instead of only patching the running container.

Agents:

  • deploy_app answers within 45 seconds, or the wait_seconds it’s given, up to 240. A deploy still going carries on in the server, and the new deploy_status waits for it. Codex stops a call after five minutes, and a plugin can’t give it longer.
  • Started in a plugin’s own directory, as Codex and every Agent Plugins client start it, jiayang mcp never deploys from there. It goes by PWD, the directory the client was started from, and otherwise says to set JIAYANG_MCP_ROOTS.

Deploys:

  • A plain Worker can import npm packages. It’s bundled with wrangler, like TypeScript.
  • A static site’s own 404.html is served for paths with no file.
  • SvelteKit and Astro apps no longer fail on Cloudflare’s disabled default cache. A SvelteKit app without the Cloudflare adapter is told which adapter to add.
  • Go and Rust images carry the project’s files beside the binary. Go builds use Go 1.27 and fetch a newer toolchain when go.mod asks for one.
  • Generated container images run under tini, so they stop cleanly.
  • A failed Docker build shows Docker’s last lines. An app that --create made is deleted again when its deploy fails.
  • The wrangler config is checked before the build, and the plan’s app count before a --create build.

Smaller:

  • Tokens default to 30 days, the most a CLI session gives them. token list says when a token’s maker caps what it can do.
  • jiayang audit lines say who did what to which app.
  • Clearer messages for env changes, ports, credentials in a build, and the terms to accept.
  • MCP tools have titles, name each other rather than CLI commands, and mark app output as data in structured results too.

First release, so there is nothing to upgrade from.

@jiayang-cloud/sdk on npm. Its docs.

  • requireUser and verifyIdentity refuse a token whose aud is a list, even one holding the app’s id. The edge writes one string, and requireWebhook already refused a list.
  • An issuer or key set on http is refused unless env.JIAYANG_DEV is "1", and even then only on this machine (127.0.0.1, localhost or [::1], and for the keys host.docker.internal too). jiayang dev sets it for the app it runs, from CLI 0.1.11. The platform’s issuer and keys are https and it never sets JIAYANG_DEV, so a deployed app that still points at jiayang dev refuses everyone, and asks nobody for keys.
  • envFromProcess() reads JIAYANG_DEV with the rest.
  • An app that checked tokens against keys of its own over http, outside jiayang dev, is now refused. That is why this is 0.3.0.
  • A caller has agentName: the name of the workspace’s agent that made the request, or null for a person, a bypass token or a scheduled job. isAgent(user) says whether an agent called. Decide what an agent may do by sub, which is agent:<agent id>. The name can change.
  • An agent’s identity token with no name, an empty one, or an empty agent id is refused, as a person’s with no email is. The platform always sends one.
  • User has a new required field, so code that builds a User by hand (in tests, say) needs agentName: null. That is why this is 0.2.0.
  • The README is rewritten in plain words. Nothing in the SDK’s behaviour changed.
  • The Express adapter’s 401 and 403 carry Cache-Control: no-store, as toResponse() already did.
  • A 403 says forbidden: this needs editor as plain text, the same body every SDK answers, rather than forbidden.

The first version on npm. 0.1.0 was tagged but its publish failed, so it was never released. The code is the same as 0.1.0 below.

First release, so there is nothing to upgrade from.

  • requireUser and verifyIdentity check the identity token the platform sends with a person’s or a bypass token’s request, with Express, Hono, Next and node:http adapters.
  • requireWebhook and verifyWebhook check the token it sends with a webhook delivery whose signature it verified, and name the provider. The adapters are requireWebhook for Express and Next, webhook and getWebhook for Hono, and requireWebhookFrom for Node’s own headers. Each kind of token is refused where the other is expected.

jiayang on PyPI. Its docs.

  • require_user and verify_identity refuse a token whose aud is a list, even one holding the app’s id. The edge writes one string, and require_webhook already refused a list.
  • A request with two X-Jiayang-Identity headers is refused, as the Node SDK refuses it. It read the first.
  • An issuer or key set on http is refused unless JIAYANG_DEV is 1, and even then only on this machine (127.0.0.1, localhost or [::1], and for the keys host.docker.internal too). jiayang dev sets it for the app it runs, from CLI 0.1.11. The platform’s issuer and keys are https and it never sets JIAYANG_DEV, so a deployed app that still points at jiayang dev refuses everyone, and asks nobody for keys.
  • Config has dev, which Config.from_env reads from JIAYANG_DEV. A Config with an http issuer or key set raises Unauthorized when it’s made, unless dev is true. That is why this is 0.3.0.
  • A Config made with an empty app id, issuer or key set URL raises Unauthorized saying they must be set, as Config.from_env does, rather than that they must use https.
  • User has agent_name: the name of the workspace’s agent that made the request, or None for a person, a bypass token or a scheduled job. user.is_agent says whether an agent called. Decide what an agent may do by sub, which is agent:<agent id>. The name can change.
  • An agent’s identity token with no name, an empty one, or an empty agent id is refused, as a person’s with no email is. The platform always sends one.
  • agent_name defaults to None, so code that builds a User by hand keeps working.
  • The README is rewritten in plain words. Nothing in the SDK’s behaviour changed.
  • A 403 says forbidden: this needs editor as plain text, the same body every SDK answers: Flask and Django said forbidden: editor as HTML. FastAPI’s is that text as its JSON detail.

First release, so there is nothing to upgrade from.

  • require_user and verify_identity check the identity token the platform sends with a person’s or a bypass token’s request, with Flask, FastAPI, Django, Streamlit and Gradio integrations.
  • require_webhook and verify_webhook check the token it sends with a webhook delivery whose signature it verified, and name the provider. The integrations are webhook_required and get_webhook for Flask, the webhook dependency for FastAPI, and webhook_required for Django, which exempts its view from the CSRF check. jiayang.aio has both calls. Each kind of token is refused where the other is expected.

the jiayang.cloud/sdk module. Its docs.

  • RequireUser and Verify refuse a token whose aud is a list, even one holding the app’s id. The edge writes one string, and RequireWebhook already refused a list.
  • A request with two X-Jiayang-Identity headers is refused, as the Node SDK refuses it. It read the first.
  • An issuer or key set on http is refused unless JIAYANG_DEV is 1, and even then only on this machine (127.0.0.1, localhost or [::1], and for the keys host.docker.internal too). jiayang dev sets it for the app it runs, from CLI 0.1.11. The platform’s issuer and keys are https and it never sets JIAYANG_DEV, so a deployed app that still points at jiayang dev refuses everyone, and asks nobody for keys.
  • Config has Dev, which ConfigFromEnv reads from JIAYANG_DEV. NewVerifier returns an error for an http issuer or key set unless Dev is true. That is why this is 0.3.0.
  • User has AgentName: the name of the workspace’s agent that made the request, or empty for a person, a bypass token or a scheduled job. user.IsAgent() says whether an agent called. Decide what an agent may do by Sub, which is agent:<agent id>. The name can change.
  • User marshals agent_name too, null when empty, as the other SDKs write it.
  • An agent’s identity token with no name, an empty one, or an empty agent id is refused, as a person’s with no email is. The platform always sends one.
  • A User written as an unkeyed literal (User{"user", ...}) no longer compiles. Name the fields.
  • The README is rewritten in plain words. Nothing in the SDK’s behaviour changed.
  • Requires answers its 403, forbidden: this needs editor, with no newline after it, the same body every SDK answers.

First release, so there is nothing to upgrade from.

  • RequireUser, Verify, Middleware and Requires check the identity token the platform sends with a person’s or a bypass token’s request.
  • RequireWebhook, VerifyWebhook and WebhookMiddleware (with WebhookFrom) check the token it sends with a webhook delivery whose signature it verified, and name the provider. Each kind of token is refused where the other is expected.
  • User and Webhook marshal to JSON with the names the Python and Rust SDKs use: kind, sub, email, role and workspace_id, and provider, pattern, delivery, signed_at and workspace_id. An empty email or delivery id is null, and signed_at is unix seconds or null.

the jiayang crate. Its docs.

  • require_user and verify refuse a token whose aud is a list, even one holding the app’s id. The edge writes one string, and require_webhook already refused a list.
  • A request with two X-Jiayang-Identity headers is refused, as the Node SDK refuses it. It read the first.
  • An issuer or key set on http is refused unless JIAYANG_DEV is 1, and even then only on this machine (127.0.0.1, localhost or [::1], and for the keys host.docker.internal too). jiayang dev sets it for the app it runs, from CLI 0.1.11. The platform’s issuer and keys are https and it never sets JIAYANG_DEV, so a deployed app that still points at jiayang dev refuses everyone, and asks nobody for keys.
  • Config has a new public field, dev, which Config::from_env reads from JIAYANG_DEV. Verifier::new refuses an http issuer or key set unless it’s true. A Config { .. } literal needs dev: false. Config is Default now, so ..Default::default() works too. That is why this is 0.3.0.
  • User has agent_name: the name of the workspace’s agent that made the request, or None for a person, a bypass token or a scheduled job. user.is_agent() says whether an agent called. Decide what an agent may do by sub, which is agent:<agent id>. The name can change.
  • An agent’s identity token with no name, an empty one, or an empty agent id is refused, as a person’s with no email is. The platform always sends one.
  • User has a new public field, so a User { .. } literal needs agent_name: None. That is why this is 0.2.0.
  • The README is rewritten in plain words. Nothing in the SDK’s behaviour changed.

First release, so there is nothing to upgrade from.

  • Verifier::require_user and Verifier::verify check the identity token the platform sends with a person’s or a bypass token’s request. The axum feature adds the Jiayang layer and the User extractor.
  • Verifier::require_webhook and Verifier::verify_webhook check the token it sends with a webhook delivery whose signature it verified, and name the Provider. The axum feature adds the JiayangWebhook layer and the Webhook extractor. Each kind of token is refused where the other is expected.

@jiayang-cloud/client on npm. Its docs.

  • A share or a new member’s reply says which day’s budget stopped the invitation email, when one did: budget_spent is workspace, sender or platform, beside invited: "over_budget".
  • A share in the role the person already had says unchanged: true. Nothing changed and nothing was logged.
  • First release. A client for the Jiayang Cloud API: workspaces, members, apps, versions, deploys of Workers and static sites, sharing, bypass tokens, the audit log, secrets and config values.
  • Signs in with a CLI session: token, JIAYANG_TOKEN, or the one jiayang login saved.
  • Tries reads again after a failure on our side or a 429, and never sends a change or a deploy twice.
  • Sends a deploy’s lock files and .jiayang-allow for its scan, when given them as scan.
  • Sends a saved CLI session only to the API it was made by.
  • Asks for the app’s key-value storage and queue with a Worker deploy, as jiayang.json does: kv and queue.

jiayang-client on PyPI. Its docs.

  • A share or a new member’s reply says which day’s budget stopped the invitation email, when one did: budget_spent is workspace, sender or platform, beside invited: "over_budget".
  • A share in the role the person already had says unchanged: True. Nothing changed and nothing was logged.
  • First release. A client for the Jiayang Cloud API: workspaces, members, apps, versions, deploys of Workers and static sites, sharing, bypass tokens, the audit log, secrets and config values.
  • Trusts what the operating system trusts, through truststore, its one dependency.
  • Signs in with a CLI session: token, JIAYANG_TOKEN, or the one jiayang login saved.
  • Tries reads again after a failure on our side or a 429, and never sends a change or a deploy twice.
  • Sends a deploy’s lock files and .jiayang-allow for its scan, when given them as scan.
  • Sends a saved CLI session only to the API it was made by.
  • Asks for the app’s key-value storage and queue with a Worker deploy, as jiayang.json does: kv and queue.