Repository navigation
AppTown v1.0.0-rc.6
Pre-releaseFlokkit AppTown v1.0.0-rc.6
The sixth candidate for 1.0, and the first under the product's new name,
Flokkit AppTown (AppTown for short; it was Flokkit, and the code called it
"forge"). It replaces RC5 as the candidate running in production with the
maintainers, and the two-week run before 1.0 starts again on it.
RC6 renames everything people, agents and apps see from "forge" to
"AppTown", and fixes the app contract that 1.x keeps stable (version 2). It
makes each stock need give an app the same values on every deployment
target. It backs up object storage and Portainer deployments, and gives
every deployment its own database and storage credentials. It adds a
one-command desktop trial over HTTPS. It closes what 1.x could not change
later, removes features nobody used, and fixes defects found in the RC5 run
and in a first desktop trial.
Since 22 October 2026 the code changes on GitHub, at
github.com/flokkit/apptown, one pull request per change.
In short
- The product is AppTown, and so are its names. The commands are
apptown,apptowndandapptown-worker. Settings areAPPTOWN_*,
headersX-AppTown-*, and tokens startapptown_. The repository folder
is.apptown/. AppTown reads none of the oldFORGE_*names. - Apps get only the new names:
APPTOWN_ORIGINS,APPTOWN_RELEASE,
APPTOWN_BROWSER_ENV*,window.__APPTOWN_ENV__and/_apptown/, and no
FORGE_*. - The app contract is version 2: memory in
Mi/Gi, cpu in cores or
millicores, and${needs.<need>.<VARIABLE>}to pass a need's value under
another name. It refuses values, names and fields that 1.x could not give
a meaning later, and says what to write instead. - Every stock need gives an app the same connection values on every
target, ascontract-reference.mdsets out. Each deployment has its own
database and storage passwords. - Backups now cover object storage and Portainer deployments, and were
proven on a real Docker host, App Platform and Portainer. Restore
rehearsals run on the app's own host when no host is kept for them. - What AppTown makes for a deployment is named by the deployment's id,
underapptown-, withapptown.*Docker labels. - Sign-in is the default.
apptowndstarts with-auth internalunless
told-auth open. - Settings an administrator changes are set in AppTown, not in flags.
Fiveapptowndflags are gone, and the flags that remain are promised
for 1.x. - Features nobody used are removed: the backlog, project export, the
check-only worker, webhook triggers and others (see "Removed"). - Try it with one command on your own computer, over HTTPS. It installs RC6.
- Behind a company's TLS-inspecting proxy, AppTown's own connections can
trust that company's certificate authority. The containers AppTown starts
do not trust it yet. That comes in RC7. - No automatic upgrade from a release candidate. RC6 is for new
installs. See "Upgrading from RC5". It has thirteen database migrations
(153 to 165).
What changed
The new name
- The product is called Flokkit AppTown, AppTown for short. The web
interface, the server's and the CLI's messages, the guides, the README,
NOTICEand the GitHub repository (flokkit/apptown) use it. The Go
module isgithub.com/flokkit/apptown. The container images are
ghcr.io/flokkit/apptown,apptown-workerandapptown-agent. - Commands, install paths and settings. The daemon is
apptownd, the
CLIapptown, the workerapptown-worker, and the restore gate
apptown-gate. A server install uses/opt/apptown,
/etc/apptown/apptownd.env,/var/lib/apptownandapptownd.service(a
worker:/opt/apptown-worker,/etc/apptown-worker,
apptown-worker.service). Every daemon flag is set asAPPTOWN_<FLAG>.
FORGE_variables are not read. The operator secrets are
APPTOWN_WEBHOOK_TOKENandAPPTOWN_APPS_DOMAIN. The agent image's
default tag isapptown-agent. - The built-in database of a new install is the container
apptown-db
on the volumeapptown-data-apptown-db, and the database inside is
apptown.db.envrecords these names, so an install made before 1.0
keeps its own. The trial keeps its data in/var/lib/apptown/data. The
SSH host alias for an attached Docker host isapptown-target-<name>. - The CLI and agents. The CLI reads
APPTOWN_URL,APPTOWN_TOKEN,
APPTOWN_USERand the rest, and its credentials from
~/.config/apptown/credentials. Agent steps and chats getAPPTOWN_*
variables and see AppTown's inputs at/apptown/inand/apptown/state.
The MCP server is namedapptownand its scopes areapptown:*. - What leaves AppTown. Request and response headers are
X-AppTown-*
(andAppTown-Restore-Token,AppTown-Gate,AppTown-Head); new commits
carryAppTown-*trailers (commits already written keepForge-*); new
tokens startapptown_(apptown_invite_,apptown_mcp_,apptown_git_
and so on); the session cookie isapptown_session; metrics are
apptown_*; the OpenVEX document namesapptown:project/<slug>. AppTown
names itselfapptownto outside systems it sets up from now on (a
registry login, a Git remote user, a GlitchTip team). Outside objects that
already exist keep their names. - AppTown's own acts read as AppTown. The audit log, a target's History
and the Usage page show AppTown's own actions as "AppTown"; the stored
records are not rewritten. - The guides were renamed and checked.
running-a-forgeand
what-forge-is-forarerunning-apptownandwhat-apptown-is-for. Every
shipped guide was checked against the code and rewritten where it was wrong
or out of date (for example,apptown devwrites.apptown/dev.envand
.apptown/Procfile, and a preview stops eight hours after it was last
looked at). The roadmap guide is folded into "What 1.0 promises", under
"Not in 1.0". - The guidance, workflows and packs agents read say AppTown, and
messages no longer cite design-document paths.
Names AppTown gives what it makes
- Named by the deployment's id. Two deployments could share a
container, a network and a database volume on a Docker host: project
shopwith deploymenteu-mainand projectshop-euwith deployment
mainmade the same name. Everything AppTown makes for a deployment is
now named from its key, the last 12 hex digits of its id:
apptown-dep-<key>for the app,apptown-svc-dep-<key>-<name>for its
services,apptown-need-dep-<key>-<need>for a need's data, and so on.
Portainer stacks, App Platform apps, database clusters, Spaces keys and
buckets are named the same way. - Docker labels are
apptown.*. A deployment's containers, network and
volumes also carryapptown.projectandapptown.deployment.name, so a
person can tell fromdocker pswhose they are. AppTown never reads
those two. - Moving an older deployment. A deployment made before this keeps
working under its old names.apptown move-names <project> <deployment>
moves it. AppTown releases what it runs again and stops it. It copies
each data volume to the new name and checks every file, owner, mode and
link of the copy. Then it switches the record and starts the app under
the new names. The old volumes stay on the host until someone deletes
them. A copy that does not check out puts the old app back. Portainer
deployments are not moved: take one down and release it again. - Leftovers from older releases. At start, AppTown and each worker
remove the throwaway containers an older release left withforge.*
labels (previews, step and chat containers, checks, tasks). A chat or
preview open at that moment is made again when next used. A deployment's
own containers and volumes, and the built-in database, are not touched. - Throwaway containers take their anonymous volumes with them. Checks,
tests, tasks, agent steps, a step's services and copy jobs were removed
without their anonymous volumes. A busy host gained hundreds to thousands
of unused volumes a day. These are now removed with-v. Named volumes,
which hold data, are never touched. Standing deployments are still removed
without-v, and AppTown does not rundocker volume prune. Volumes
already left on a host stay until someone removes them. - These names are not promised. "What 1.0 promises" says how AppTown
names and labels what it makes may change in 1.x. Names already given
stay.
The app contract
-
Fields that do nothing are refused, by name. A version-2
.apptown/app.yamlis refused if it usesseed;healthcheckon the
public part; the healthperiod,timeout, thresholds orchecksDeps; a
tcporexecreadiness probe;dataDiron a part that is not public; or
setsPORT,APPTOWN_ORIGINS,DATA_DIRorAPPTOWN_RELEASEin an
environment. Each refusal says what to do instead. These were accepted
and ignored, or behaved differently by target; refusing them now lets a
later release give them a meaning without changing what existing apps do. -
What a 1.x release may still change is listed in the compatibility
guide: the limits it names (health timings and probe kinds, Portainer init
ordering, where integration values arrive,seed, origins anddataDir
delivery) may be lifted; nothing else in the contract changes meaning. -
APPTOWN_ORIGINSandcommandare written down: the origins format,
and that a stringcommandruns withsh -c. -
One exact app contract.
contract-reference.mdsays what an app must
do and what AppTown gives it: the files read, what a build sees, the
process, the environment by target and part, startup order, what arrives
through the front door, health and static sites. Where targets still differ
(health checks, startup order on Portainer), it says how. "What 1.0
promises" names it as what 1.x keeps stable. -
The contract's names (flag day). The repository folder is
.apptown/
(the contract is.apptown/app.yaml). Apps getAPPTOWN_ORIGINS,
APPTOWN_RELEASEandAPPTOWN_BROWSER_ENV*, the browser global
window.__APPTOWN_ENV__, and the static files/_apptown/env.jsand
/_apptown/release. AppTown gives apps none of theFORGE_*names,
__FORGE_ENV__or/_forge/any more. Workflows and packs say
apiVersion: apptown.dev/v1; a stored one keeps the version it was
written with. New changes and runs use the branchesapptown/change-Nand
apptown/run-N; earlier ones keep theirs. The stock platform pack is
apptown, and the checktrusts-forge-front-dooristrusts-front-door.
Revisions recorded before the upgrade (releases, backups) are read at
.forge/app.yaml, as they were written. -
Values reach the app exactly as written. An environment value must be
text, a whole number or true/false. A value YAML would read as something
else is refused and should be quoted:3.10used to arrive as3.1, and
an empty value as<nil>. Values accepted before reach the app as they
did. -
Names are checked. Environment names are letters, digits and
_, not
starting with a digit. Names startingAPPTOWN_are kept for AppTown. A
secret can no longer be namedPORT,DATA_DIRor another variable
AppTown sets: such a value used to win on a Docker host and lose on other
targets. Part and init step names are 2 to 32 lower-case letters, digits
and hyphens, as App Platform requires. Parts, init steps and needs share
one set of names.app, and names startinginit-orapptown-, are
refused. Every init step needs a name, because a secret is scoped to an
init step by its name. -
Fields that were ignored are refused. A static site refuses
environment,command,dataDirandhealthcheck.portslists the
one port a part listens on: a second entry or a host port such as
3000:8080is refused.secrets.specmust name a file inside the
project. -
A project's address is fixed. A project's slug (as in
shop#12) can
no longer be changed once the project exists. Renaming it left the
repository folder, containers, volumes and backups under the old name, and
a new project given the old slug took over the old repository. The display
name, icon, line and group can still change. -
No
VOLUMEin an app's Dockerfile. AVOLUMEline makes Docker
create a new unnamed volume for every container started from the image:
checks, previews and releases. AppTown does not back these up or move
them. Thebuild/container-imageguidance, which every stock pack that
builds an image includes, now says to leaveVOLUMEout. Its new check,
no-volume, fails anyVOLUMEin the Dockerfile's final stage, even at
the data folder. It says to remove the line, and to declare the folder as
dataDirif the app keeps data there. A Dockerfile whose heredocs the
check cannot follow is "not judged". AVOLUMEfrom the base image, and
Dockerfiles in other build folders, are not judged. Projects get the
check when they adopt the new pack version. -
The contract is version 2. Memory is written in Kubernetes binary
units only (512Mi,2Gi); a bare512Mis refused with the spelling to
use, because Kubernetes and Score readMas decimal. Cpu may be
millicores (500m). A version-1 contract (or one with no version) keeps
readingMandGas MiB and GiB wherever it is read. Deployment memory
overrides takeMi/Gi, and pages show memory inMi/Gi. -
Environment values may read a need's values, as
${needs.<need>.<VARIABLE>}(version 2), for an image that expects its own
names:WORDPRESS_DB_HOST: "${needs.mariadb.DB_HOST}". The need's own
variables are still given. It is the same on every target; on App Platform
a wired value is a secret.$${needs.writes the literal text. A variable
the need does not give, or anllmvalue, is refused before a deploy.
apptown devgets the wired values too. A value that already contained
${needs.is now replaced; no stock starter does. -
AppTown keeps its own contract, not Score. The decision
(design/decisions/app-contract-and-score.md) takes Score's Kubernetes
units and value wiring, and says what would make AppTown export, import or
adopt Score. A Score exporter or importer would not change the 1.x
contract. -
One architecture per AppTown. The app contract says it: workers and
targets run one CPU architecture, a release to another is refused before
anything is built, and a project moved to another architecture builds its
releases again.
Needs
-
A need's default version is fixed for 1.x. A need declared without a
versiongets PostgreSQL 16, MariaDB 11.4.13 or Redis 7 in every 1.x
release, so an app is never moved to a newer server on its old data.
Writeversion:to choose another. -
MariaDB starts reliably. Its first start used to give up on a busy
host after about 30 seconds and leave the app without its database. The
need's start script now sets up the data folder itself, and at every start
makes the app's database and user if they are missing. A first start takes
about 3 seconds. A standing MariaDB failed from its second start on most
Linux hosts, and a small one was killed on its first start. Both are
fixed. Passwords and database names with quotes or backslashes reach the
server as written. -
A service Docker is restarting is waited for, within the same time
limit, instead of being failed as unhealthy. -
A need takes only the parameters its catalogue lists, plus
disposable,sizeandresources. Theproperties:pass-through is
refused, andkind,prefixandasare reserved for naming two needs of
one kind later. -
AI models (
llm, Experimental) giveLLM_API_KEYandLLM_BASE_URL,
an OpenAI-compatible chat-completions API; OpenRouter answers it today.
The OpenRouter-named variables are gone. -
Error reporting gives
SENTRY_DSNonly.GLITCHTIP_DSNand the
Spring-only setting are gone (the Spring setting is in the java-spring
guidance). -
Object storage (
s3) is a private store with an S3 API, not public
file serving: no public address, and presigned URLs are outside the
contract. Serve objects through the app. -
Words: a need is what the app declares; a service is what a need
gets in a deployment or preview; a need is fulfilled by the target or
through an integration. Settings › Services lists every need and says what
fulfils it. Error reporting is an integration, not a need. -
One contract per need, the same on every target. Each stock need
lists what it gives the app underprovides:, and the services-and-data
guide has the table (a test holds it to the catalogue). "What 1.0
promises" promises those names through 1.x. A contract is refused at its
check, at release admission and when a preview boots if it puts an
integration such aserrorsunderneeds:, sets a password AppTown sets,
or selects two needs that give the same variable. Redis givesREDIS_URL
only, and MariaDB addsDB_SSL_MODE(DISABLEDorREQUIRED). -
A need that is not healthy fails the boot. On a Docker host the boot
used to start the app beside a need whose health check was failing. Now it
stops before any init step or part starts and names the need. A database
that is still initialising counts as starting until the boot's startup
limit runs out, so a slow first start is not refused. -
Object storage on App Platform. An app that needs
s3gets a Spaces
bucket of its own and a key that reaches only that bucket. AppTown makes
the bucket with a short-lived key that it deletes straight after (and
deletes one an interrupted release left behind). App Platform's stock needs
arepostgresands3. -
Each deployment has its own need credentials. On a Docker host, on
Portainer and in a preview, each deployment and each preview has its own
password for Postgres, MariaDB and Redis, and its own keys for object
storage. Before, every deployment used the catalogue's fixed values (app,
local/localsecret) and Redis had no password. Redis's password is in
REDIS_URL. AppTown derives the values from its secret store's key and
does not store them, so anyone who holds AppTown's database can work them
out, as they can read the built-in store's values. A failed boot's kept
output has them replaced with[secret]. The servers AppTown starts beside
its own steps (tests, agent steps,apptown dev) keep the fixed values.
App Platform keeps the credentials DigitalOcean makes. -
A deployment's Postgres user owns its database and nothing more. On a
Docker host, on Portainer and in a preview the app's user used to be the
server's superuser. It is now an ordinary login that owns its database, its
publicschema and everything in them, and can use the extensions Postgres
marks trusted (pgcrypto,citext,pg_trgmand the like). It cannot
create roles or databases. The server's superuser ispostgres, reachable
only over the container's own socket, and no other role may connect to the
app's database. App Platform already worked this way. The servers beside
AppTown's own steps keep the app's user a superuser, because Django's test
runner makes its own database and Rails loads fixtures with superuser
commands. -
The s3 bucket exists before the app starts, and the app's key cannot make
one. On a Docker host, on Portainer and in a preview the store makes the
bucketappand the app's account before it reports healthy. The store's
root key is AppTown's and is never given to the app. An app that creates
its bucket at start gets a 403 there, as it would on Spaces. -
WordPress uploads go to the deployment's own
s3need. A new
wordpress-bedrockproject asks for no S3 settings, and the six settings
under Settings › Secrets are gone. Media URLs are the site's own
(/app/uploads/...), the site serves them from a private bucket, and no
object carries an ACL. Media is backed up with the database. Docker host
and Portainer only, since App Platform has no MariaDB.
Backups and restores
- Restore rehearsals run on a small install. A rehearsal used to need a
Docker host set aside for it and a backup store. When no host is kept for
rehearsals, it now runs where the app's data is: on the app's own Docker
host, or on an App Platform target's copy runner. It reads the backup from
the backup store or AppTown's own disk and checks its size and digest. The
record says which host it ran on, and the Data protection page says "not
kept for rehearsals" when it ran beside other things. There it has its own
containers, network and volumes and publishes no port, but it shares the
host's CPU, memory and disk, and its outbound network is not blocked. An
install that marks a host for rehearsals runs every one there, and a
rehearsal is refused when that host does not answer. Rehearsals run only
when a person asks. - A restored copy is always a restore test. AppTown starts it, checks it
and takes it down. Opening and extending a restored copy are removed. - Object storage is backed up through the S3 API. On a Docker host the
copy used to be a tar of the gateway's files, which lost each object's
content type and metadata, and a restore said "files copied, not verified".
The copy reads every object with its headers. A restore puts every object
back, deletes the objects the copy does not have, and checks keys, sizes,
headers and bytes, so it is verified. Object ACLs, tags and versions are
not copied, restored objects get new modification times, and an object
uploaded in parts comes back with a different ETag. An object over 5 GiB is
refused. Copies taken before RC6 still restore as files, "not verified". On
App Platform the bucket is copied on the copy runner with the deployment's
own key, and its copy is checked by filling a new S3 store on the runner.
Starting from a copy, a restored copy and a restore test fill the new
deployment's own bucket. A copy taken before RC6 holds no objects, so it is
refused for an app that needss3. A take-down deletes the bucket only
after a good copy whose check passed; otherwise it deletes the key, keeps
the bucket and says why. - Portainer deployments are backed up. Before, AppTown copied nothing
on Portainer and kept every volume at take-down. It copies a Portainer
deployment's data with the same plan and commands as a Docker host's,
nightly and after each intranet release, through Portainer's Docker proxy.
The target's API key goes in no file, argument or environment variable.
AppTown records the volumes its deploys made. A take-down deletes those
after a complete final copy and keeps any other volume the stack uses
(copied, not deleted). An environment AppTown cannot reach, or an edge
agent in async mode (which has no Docker proxy), is refused by name, and a
take-down there needs--without-final-copy. Restores and final copies on
Portainer and on Docker hosts stop only the parts that are running and
start exactly those again, so a part someone stopped stays stopped. - A need's storage survives its service being remade. When a release or
redeploy recreates a need's service it keeps the same volume, or refuses.
After a release AppTown compares the need's data with what it held before
and says if it shrank. - A release over data AppTown cannot copy needs a person's acceptance.
A release of new code onto a deployment holding data AppTown cannot copy
now is refused at both release doors and says why. The cases are a
held-data plan that cannot be read, an item AppTown cannot copy, an App
Platform target with no backup store or copy runner, and a Portainer
environment AppTown cannot reach. A person can release anyway with
apptown release --accept-uncopied-data(acceptUncopiedDatain the API),
and the release's first log line records who did and why the data could not
be copied. Redeploying the bundle a deployment already runs is not asked. - A restore runs as an operation. Restoring a backup set (from the
Backups page or the API) answers at once with the operation, which
apptown wait operationand the operation's page follow, with each step
and each item's outcome as it finishes. If AppTown restarts during a
restore, the restore ends unknown with what it had confirmed, and
AppTown does not start the app again. The record names the containers the
restore may have stopped. The restore may still be writing on the host, so
check that no restore container orpg_restoreis running and look at the
containers, then release the deployment again. The safety copy holds what
was there before.apptown executinglists running operations as well as
steps, so a deploy that waits for it also waits for copies, restores and
take-downs. - Backup checks are kept per item. A deployment's data view (its card and
apptown data) used to show every item with the newest check's result, so
a database could show a bucket's check, with "came back ... as" and nothing
after it. Each check records its item, and the view says "came back on
from into ", with "as " only when there is one.
A database's place reads "a new database on the deployment's cluster", and
a bucket's names the copy runner. The weekly check of production data is
due when any item's own last check failed, is missing or is a week old.
The "not assessed" line for outside data reads "data the app keeps
outside the needs it declares, such as a bucket or a database it reaches
with its own settings", so it no longer contradicts a covereds3need. - Starting from a copy needs every item checked. The first release of a
deployment that starts from a copy is refused unless every item it would
fill passed its last check of that copy. The refusal names the item and
its last check. A person can go on with
apptown release --accept-unchecked-copy(acceptUncheckedCopy), and the
release records it. A take-down checks its final copy as part of it, so a
whole final copy starts as before; one whose check failed for an item
needs that choice. "Checked" beside a final copy means every item came
back.
Deployments and releases
- A need's storage is kept when its service is remade, or the release is
refused. Before a release AppTown checks it can copy the data it holds
(apptown release --accept-uncopied-datareleases anyway, recorded);
after it, it compares the need's data with what it held before. - A stopped need is started, not just judged. A deploy that reuses a need container which has stopped starts it (same container, same storage) before waiting for it; if Docker cannot say whether it runs, nothing is started. A need that is not running is reported as not running, not as unhealthy.
- A failed release on a Docker host ends failed, so the next release or
a take-down can follow. A boot that failed after it started changing the
host (a migration that exits non-zero, a service that never gets healthy,
a readiness check that does not pass) was recorded as uncertain. Nothing
could settle it, and every new release and take-down was refused. Now any
failure the boot reports ends the attempt failed, on both the release and
the landing path. A failure does not undo what the boot changed. Releasing
again replaces the failed app container and reuses standing services and
their data. When AppTown loses track of an attempt, Check again settles it
from what the host says. Only a host that cannot be asked leaves it
uncertain. One case reads wrong, and the deployment guide says so: if
AppTown stops after a healthy boot but before writing its record, the
attempt reads failed while the new container runs. The next release
replaces it. - A release built on AppTown's own Docker is published. An AppTown with
no worker builds a landing's release on its Docker host. It recorded those
images by local id and never pushed them, so releasing them to Portainer
or a bucket website failed. Now, when the project has a container
registry, the landing publishes each image there, as a worker's build is,
and the release records it by digest. If the registry refuses, the step
says the new version is running and was not published. Releases recorded
before this are not published later: land a new change. - A worker changes where a job runs, not what it produces. Intranet
releases (apptown release <project>) no longer build and push images
themselves. They ship only a release a landing published to the project's
registry, and refuse one that was not, at the request. Before an agent
step, AppTown merges main into the change on its own machine as well as on
a worker, and tells the agent. If an uncommitted file blocks the merge, the
step stops before the agent starts. An agent's private Docker is not
logged in to any registry, with or without a worker. - Portainer gets the integration settings a Docker host gets, such as
SENTRY_DSN,FEEDBACK_URLandREGISTRY, on the public service only.
The app's own environment and secrets win. The release log names the
settings but not their values. - Portainer deployments report whether they run. AppTown reads each
Portainer environment's app containers once per sweep. A list it could
not read shows unknown, never stopped. - A preview restarts when its secrets change. A preview asked for again
with the same commit kept running with the old secret and integration
values. The comparison now includes each secret's name, store and version
and a keyed fingerprint of the values, never the values themselves. Every
running preview starts again once, the next time it is opened. - A fix-forward can land past a merged change whose deploy failed. The
earlier landing no longer holds the project's landing slot once its merge
is recorded; when the later one ships, the earlier change reads "shipped
with a later change". A recorded merge is final: a landing never merges
twice. - Releasing to a Portainer deployment by name works, with its needs.
apptown release <project> <deployment>and a card's Deploy latest
failed for every Portainer deployment ("portainer renders no artifact of
its own"). They build the same stack as the intranet release, needs
included. They refuse an image that was not published to the project's
registry by digest, an environment whose platform is unknown or differs
from the bundle's, and a second deployment of one project on the same
Portainer target. - The Portainer environment is a setting of the target. The intranet
target's environment is set under Edit target on its Infrastructure page.
A new install starts withlocal. Before, it was alwaysprd-forge, and
AppTown set it back at every start. - A
$in a value reaches Portainer andapptown devas written.
Secrets, contract environment values, data folders, build contexts and
images in the Compose files AppTown writes used to be read as variables, so
pa$wordarrived aspa. - A value App Platform would change is refused before the deploy. App
Platform replaces${NAME}in any environment value, secret or not, when
NAME is one of its own variables, and has no way to escape it. A deploy to
App Platform stops before anything is made when a secret or declared
environment value contains${…}(other than a${needs.…}reference),
naming the variable and the part. Before, the app silently got the changed
value. - Only
mainis served at a project's address on an attached Docker
host. On a Docker host attached with an ingress domain,mainis served
athttps://<project>.<domain>. Any other deployment of the project, such
asstagingor a fresh copy, is shown at the host's address and its own
port,http://<host>:<port>, which people reach only if the host's firewall
lets them. Before, such a deployment was given main's address too and took
about half of main's visitors. Addresses ofmain, the built-in host,
Portainer and App Platform do not change. - Every deployment on a Docker host keeps one port. A deployment keeps
the host port it got at its first start, whether a landing or a release
started it. Before, a deployment other thanmainthat had been released
only once got a new port from Docker every time its container started (a
restore, a health restart, a host or Docker restart). AppTown kept probing
the old port, so it restarted the deployment again and again, and the card
showed an address that did not answer. Previews still take a port Docker
picks, and AppTown asks Docker for it each time.
Changes and checks
-
A landing's secret scan reads every commit it adds to main. The start-up
step that set up the stock scanners dropped gitleaks' history command, so
every landing scanned only its final files. A token committed and then
deleted in the same change was merged into main's history. Now a finding
in any added commit counts. AppTown reads the commit range itself and
treats a range it cannot read as an error, because gitleaks reports that
as "no leaks found". The scanner guide says what to do when a change has
committed a secret and later deleted it. -
A person can fix a blocked landing without a model. For a change no
agent works on,apptown sendbackstops the landing and puts the change
back in progress, so its person can push a fix and land again. -
Chats are refused when no model is set up, with the same sentence
workflows give. Before, the chat opened and every message failed. -
A change starts when it is opened. "Add to backlog" and the proposed
state are removed, because a proposed change could not be worked on. An
idea for later belongs in the team's ticket tracker. A request for a
proposed change is refused. A proposed change left on an install is closed
as abandoned by migration 165. -
A step gets private Docker only when it declares
docker: true. At
every start AppTown used to add private Docker to any library workflow
whose step used the implementation skill, and publish that as a new
version. A workflow now keeps the text it was saved with. -
Licence scans no longer fail beside the vulnerability scan. Both trivy
scans shared one on-disk cache, which trivy lets one process use at a
time, so the licence scan sometimes gave up and blocked the landing. The
stock trivy scanners keep their scan cache in memory. The vulnerability
database is still cached on disk. -
Large Git pushes are accepted. AppTown's Git endpoint refused the
chunked uploads Git sends for pushes over 1 MiB, soapptown checkand
change-ticket pushes failed for commits with large files. Each push is
limited by-import-bundle-max-bytes(2 GiB by default). A larger one gets
HTTP 413, andapptown checksays the commit is larger than this AppTown
accepts. -
An approval counts people by their accounts. A vote AppTown cannot tie
to an account does not count. -
A stage with missing evidence cannot advance. Every stage records the
checks it expects when it opens.apptown recheck-stageand "Run the
checks again" are removed, and a run whose stage is missing evidence says
it should be abandoned.apptown recheckfor a landing's failed gates now
names only the gates that failed. -
Workflow rules are exact. A step's
failOnmust below,medium,
highorcritical. A scan step with nofailOnfails on every finding
it may gate on; a custom workflow that relied on an image scan's quiet
highshould writefailOn: high. A pack version may only name guidance
blocks, workflows and policies that are in the library, so it pins each
one. -
Accept an adoption in advance. When you adopt a version from a what-if,
you can say yes up front: "accept it if it changes no code and every step
and check passes, none excused". AppTown casts that yes as yours, with the
sentence you were shown, only when it has witnessed the condition; anything
less waits for a person. An approval offers this only when its workflow
declares what an advance yes means (inAdvance); stock quick-change,
implement and land do. Agent tokens, connected apps and chats cannot give it. -
A landing starts its own preview when a check needs the app running and
no preview is proven to run the commit being landed. If the preview cannot
start, the check says "could not check" with the reason and holds the
landing. -
A change can repair an app whose
.apptown/app.yamlAppTown rejects.
The agent step runs without the app's services and is given the error as
the job; tests, previews, landing and release still refuse the bad file. -
Adopting from a what-if starts the adoption's run, can move paired packs
together and the project's other workflows to their newest versions, and
says when a rule moves back to an older version. What-ifs have their own
list, and a project's result is a score rather than a bare "could not
assess". -
Approvals show screenshots of the change's preview (desktop and phone),
taken at the change's commit. -
The boot check covers the home page, not only the health address, and
stock PHP packs no longer display errors to visitors. -
An adoption that needs no code change goes through without an override.
When a project adopts a new way of working whose checks already pass, the
agent step passes with "nothing to change" and says why, a person accepts
it as usual, and the landing (the step that publishes accepted work)
checks the new acceptance checks before the project moves over. Nothing is
merged. Before, a person had to override the agent step. An ordinary change
whose implementing step changed nothing still fails "made no change". The
change's brief shows what each new check expects, and the reviewer accepts
an empty diff when the code already meets the request. -
A landing whose branch is already on main is refused when main moved
after its checks. It used to record main's newer head as its result. It
is refused with "the default branch moved since this landing's checks",
as a new merge is. -
Skipped tests are shown. When the test command writes a JUnit XML or
go test -jsonreport to$APPTOWN_TEST_REPORT, the tests check records
how many tests passed, failed and were skipped. Go projects on the detected
command get this with no change. A pass with skipped tests, or one whose
counts are not known, reads "passed with notes" and says which. The exit
code alone still decides pass or fail. -
Approvals name the credential they came through, for example "approved
by sam through CLI token release-bot", on the change page and in
apptown trace.
Trying and installing
-
Try AppTown with one command.
curl -fsSL https://apptown.dev/try | shstarts AppTown in one Docker
container on your own computer and opens it;sh -s -- stopand
sh -s -- uninstallstop it and remove it. The script is in the
repository'ssite/folder, to read before running. It runs its own
Docker inside the container. The link it opens carries the one-time setup
token, so the token is in the container's log until the administrator is
created. To support it, an AppTown whose-agent-imagenames a registry
pulls that image when it is missing instead of building it, and a tier
domain may carry a port; before, such a domain never matched. -
The desktop trial is HTTPS too. With
apptownd -local-tls(on in the
trial), AppTown makes its own certificate authority, limited to
localhostnames and the computer's own addresses, and serves itself and
every app athttps://…localhost:7777, so apps run as they do on a server.
On macOS the try script explains why and asks before adding the authority
to your login keychain, and uninstall removes it; on Linux it links the
steps for the system store, Chrome and Firefox. Chats on the trial trust it
already. Windows is not supported yet. AppTown's checks that open an app's
preview trust this authority too. Before, they failed with "certificate
signed by unknown authority", which blocked every first build on the trial. -
Extra certificate authorities, for a company's TLS-inspecting proxy.
Some networks re-sign every outgoing HTTPS connection with a company
certificate authority. Threeapptowndflags each take a PEM file of extra
authorities, trusted beside the system's own:-trust-inference(APPTOWN_TRUST_INFERENCE): model providers.-trust-deployments(APPTOWN_TRUST_DEPLOYMENTS): apps' preview and
deployment addresses, which AppTown's checks open, and container
registries.-trust-apptown(APPTOWN_TRUST_APPTOWN): everything else AppTown
calls, such as Git hosts, integration providers and cloud provider APIs.
The same file can be given to all three. A file that is missing or holds
no certificate stops AppTown at start, naming the flag. With
-trust-apptown, git is given the system's roots and the file together,
so the system must keep its roots in one file, as Linux distributions and
macOS do; otherwise AppTown does not start. A worker takes
-trust-deploymentsand-trust-apptown. Setting up a server explains
them. These flags are not yet in the list "What 1.0 promises" keeps
through 1.x. -
The containers AppTown starts do not trust these authorities yet.
Agent, check and build steps, previews and deployed apps are not given
the files these flags name, so behind such a proxy their own HTTPS
connections still fail. RC7 adds this. A host's Docker trusts what that
host's system or/etc/docker/certs.dtrusts. -
One server with one compose file. The
ghcr.io/flokkit/apptownimage
has a one-server mode, and the repository ships a compose file that runs it
with Caddy in front for HTTPS. Model access has default addresses on a
one-server Linux install. -
Release archives. Each release publishes archives of the binaries for
installs that do not use the images. -
Supported platforms and system requirements are a guide of their own:
Linux servers (amd64, arm64); the desktop trial on Apple Silicon Macs and
Linux; current Chrome, Edge, Firefox and Safari; memory, CPU and disk
measured on a real trial. -
Running AppTown is a short guide. It gives three ways to install (the
desktop trial, one server, and a split install with AppTown alone, agents
on a worker and apps on attached Docker hosts or a cloud), which one suits
whom, and links separate guides: Setting up a server, Split install,
Deployment targets, People and roles, AppTown's own backups, Deployment
backups, Upgrading, and Monitoring. -
Release images are built for amd64 and arm64. The release workflow's
merge step joined other images' digests into the server image's tag; it
keeps each image's apart now. -
The
apptownimage as a server. SetAPPTOWN_NO_LOCAL_DOCKER=truein
its env file. Without it the image starts as a desktop trial, which needs
--privileged. -
apptown.dev serves the project's page, the try script, the one-server
compose.yamland a tour of the web interface. A release tag publishes them after its images, from
GitHub Actions with a role that can only write that site. The page shows
both ways to start: the one-command trial for your own computer, and
"Run it on a server" with the one-server compose file's three commands,
the DNS names and ports to set up first, and a link to Running AppTown. -
A tour of the web interface.
make tourphotographs a small example
team's AppTown, page by page, in light and dark. The screenshots are
committed with each release (the release script refuses one whose tour is
out of date) and published at apptown.dev. -
The source is public.
github.com/flokkit/apptownis where the code
changes, one squash-merged pull request per change. It has a README
written for the administrator who sets AppTown up for others,
SECURITY.md(how to report a vulnerability, and what to know before
sharing AppTown) andCONTRIBUTING.md. Every pull request runs the web
checks, the Go checks, the unit tests and a check that nothing private is
committed. The Docker integration tests, journeys, browser tests and race
detector run after each merge, and a tag's images and archives are built
only when they passed on that commit. For anyone runningmake checkon a
Mac, the gate refuses to start under macOS Game Mode. -
How to check a release. Setting up a server has a section with the
cosign verifycommand for the images andcosign verify-blobfor
SHA256SUMS, each tied to the release workflow for that tag. A release
made while the repository was private has no signature. -
AppTown's own build runs no npm install scripts, and every base image
in AppTown's own Dockerfiles is pinned by digest. CI checks both.
First run and the web interface
- The first-account page works for a new install. It names AppTown, and
its "Running AppTown" link opens the guide on GitHub; before, the link led
to the built-in docs, which need a signed-in user. - A first project starts building. "Build the first version" now waits
until the chat's helper is running before it sends the opening message;
before, the message was typed while the chat was still installing its
toolchain and never sent. A chat shows "your turn" only when the helper has
finished, as the server records it, not while it runs a command. - A first model key gets a model that exists. An Anthropic key's default
is the newest Sonnet in Anthropic's own model list (it was
claude-sonnet-latest, which Anthropic does not have, so every chat
failed); an OpenRouter key's is what OpenRouter's latest-Sonnet alias
names. apptown newwithout a pack says what to do next. Such a project has
no way of working, so it cannot take a change. Before, the command
suggestedapptown quick, which was then refused. Now it says to apply a
pack withapptown pack -p <slug> <pack>and lists the packs this AppTown
offers.- Smaller first-run fixes. The new-project questions are yes/no
questions; a starter that already declares Postgres says so instead of
"services skipped"; the new project's bindings no longer all show a green
tick. - Secrets integrations say what is set up. An Infisical integration on
an AppTown without Infisical settings reads "not set up" instead of
healthy; a configured one is checked with a real read, and the built-in
store by its key. A project's card and each run's record list only the
secrets stores that are available (before, every one named Infisical). - Page help. Pages that opened with a dense paragraph show the title,
one short line and a "?" beside the title. The "?" opens the explanation
and a link to the guide. It works from the keyboard and on a phone. - Home shows only what needs you. "Needs you" lists an operation you
asked for only when it failed or its outcome is not known. The Home
sentence counts the same list ("1 needs you"), and says "All quiet" only
when it is empty. Runtime badges show the state alone while it is
current, and the time it was read only when it is out of date. Project
cards with no deployment show no running or stopped badge. - The web interface offers only what exists. The release button shows
only where an intranet target is set up; a queued conformance review shows
no spinner or unknown total; pack cards name only missing integrations;
one search box in the top bar on every page, also in the narrow menu; a
failed read of a release plan is shown as failed.
Agents
- A smaller agent image. The agent image is 1.73 GB (2.66 GB in RC5,
arm64, measured 18 October). Its browser is Chromium's headless shell, and
there is nochromiumcommand any more; the chat briefing names the new
one. It no longer contains Go. A Go project uses the Go itsmise.toml
declares, as its steps and chats already did, and the clean build of a
merge-only release does the same. A Go project that declares none is told
to pin one. The scanners use semgrep 1.99.0, uv 0.13.0, Node 24 and Go
1.27.0, so a project on an older Go may be asked for formatting or vet
fixes Go 1.27 wants.
Smaller fixes
-
AppTown acts as
apptowneverywhere: its scheduler, webhooks and system
operations (new records sayapptown-system; old records keep what they
said), the chat placement, telemetry attributes (apptown.*; the dashboard
isapptown-dashboard.json), and the project it reports its own errors to
(apptown; an install that made aforgeproject should rename it). -
Settings › Services tiles are short: a badge for experimental kinds, one
line, and what fulfils it. A dependency kind may declaresummaryand
status: experimental. -
apptown diff <change>shows that change's code (project#nor its
id), asshowdoes; a run's diff isapptown diff -r <run>. Before,
snake#7was read as snake's run 7. -
"This change adds" lists what the change declares even when main's
.apptown/app.yamlcannot be read, and still shows what may be removed. -
An AppTown refuses another installation's built-in database.
apptownd
refuses to start on a database volume whoseapptown.instancelabel (or
forge.instanceon an install made before 1.0) is not the id in its data
directory'sinstance-id, or that has no label. The message names the
volume, the folder it points at and thedocker volume rmcommand.
Before, a fresh install used a volume left by an earlier one and failed
later on its password. -
A cancelled database query no longer breaks the next one. On a busy
machine a cancelled query could leave its connection holding an error,
and the next query on it failed. AppTown now checks such a connection
before using it again, and replaces it if it does not answer. -
The Infrastructure page lists a host's containers in one Docker call.
It used one per kind, each a separate ssh connection, so a small, busy
host ran past the page's time limit. -
The image reaper keeps a freshly rebuilt conformance image. A rebuild
from cache keeps the old creation time, so it looked a day old and was
removed minutes later. -
Evals. A project advanced past its pack can be copied for an eval. An
arm whose run is blocked is failed with the reason, so the queued arms
start. Adoption changes are re-run as adoption changes. An approval the
eval settles names the commit it approves, so eval arms can land. -
A step that has finished is not cancelled when its run ends. If a
step finished just as its run ended, AppTown could treat the step as lost
and cancel it. It now reads the run first, so only a step still pending or
running in an ended run is cancelled. -
The disk floor is at most 20 GiB. New work was refused below a
twentieth of the disk free, which on a 3.6 TiB disk meant refusing with
184 GiB free. The floor is now a twentieth of the disk, at least 1 GiB and
at most 20 GiB. -
Every check and every take-down with a final copy on App Platform failed
in RC5, because a check's new database name was 46 characters and
DigitalOcean allows 40. -
A refused intranet release no longer saves the hostname it asked for; the
hostname is saved once the release is admitted. -
A release's record names the attached integrations its target does not
deliver (Portainer and App Platform run the app without their values). -
The
state-behind-needsguidance check passes a repository with no app
part, such as a command-line tool or library. -
The static file server starts without warnings, and the S3 and
DigitalOcean clients keep their own connections, so another component
closing the shared pool no longer breaks their requests.
Running AppTown
-
Sign-in is the default.
apptowndstarts with-auth internal
unless told otherwise. Open mode, where a caller names itself and there is
no sign-in, needs-auth open. Every shipped install already set
internal. -
Settings an administrator changes are set in AppTown and need no
restart.apptownd's flags hold only what AppTown needs to start and what
only the machine's owner should decide:-agent-modelis gone. Choose the default model on Home and in
Integrations (model slots). With none chosen, model work is refused
until an administrator sets one up.-agent-concurrencyis gone. Each model provider's "Steps at once" in
Integrations decides it. A provider AppTown cannot read runs one step at
a time.-errors-urlis gone. Type the GlitchTip address in its form.-mirror-baseis gone. The package-mirror forms suggest the address of
a mirror already added.-portainer-environmentis gone. The intranet target's environment is
set under Edit target. An existing install keeps the name its target
records.APPTOWN_REAP=onis nowAPPTOWN_REAP=true(the flag-reap). The
valueonis refused at start, naming the variable.-trust-inference,-trust-deploymentsand-trust-apptownare new
(see "Trying and installing").
A command line that still passes a removed flag stops
apptowndat
start, naming the flag. AnAPPTOWN_variable for a removed flag is
ignored. "What 1.0 promises" lists the flags kept through 1.x. -
The CLI's exit codes. 64 means the command line is wrong (an unknown
command or flag, a missing argument); nothing is sent. 69 means AppTown
could not be reached or stayed unavailable through the CLI's retries.
Before, a bad flag exited 2, whichwaituses for "needs a person", and
an unreachable AppTown exited 1, "failed". A refusal is still 1. -
apptown wait shop#12waits on change 12 of shop. Before, it waited on
run 12. Inwait, theshop#12form and a bare number name a change; a
run is named by its id. -
A webhook token or apps domain set under a
FORGE_name is reported
as missing, and the error asks for theAPPTOWN_name. -
db.envmust holdAPPTOWN_DB_URL,APPTOWN_DB_PASSWORD,
APPTOWN_DB_CONTAINERandAPPTOWN_DB_VOLUME. A file missing any of
them is refused with the missing keys named, and left as it was. -
Tokens made before tokens had a purpose are revoked (migration 161).
They were already refused when used. Every row is kept, with when it was
last used.
Removed
These had no users, or existed only for records on the maintainers' two
installations, whose data was checked or migrated first.
- Project export (
apptown export-projectand its API). Nothing could
import an export. - The backlog ("Add to backlog" and the proposed state).
- The dedicated check-only worker (
-check-worker, the worker's-role). - The standalone
apptown-check,apptown-deployandapptown-console
programs. -drain-local-docker. To switch to no local Docker, stop AppTown, make
sure no local work is left, and start it with-no-local-docker(the
workers guide).-featuresand the "Start clean" button on the Conformance page.-backfill-recorded-main. Every project has its recorded main.- Creating, editing and promoting change-catalogue entries. The catalogue
isstock/catalog.yaml, shipped with each release. Listing and applying
entries work as before. - The workflow-drafting endpoint and its model slot, the "simple change"
endpoint, and webhook triggers (on: webhook). - The one-time ownership inspection.
- Routes nothing called: pack picking, revoking a project deletion, a
library workflow's history, removing a member by name, listing secret
stores, renaming a user, per-project extensions, moving a project to
another group, and/items/{id}. - The same-machine probe behind the host-memory bar. The host's own memory
is shown only for the built-in target, when its total matches Docker's.
Elsewhere it shows as not known. apptown recheck-stageand "Run the checks again" (see "Changes and
checks").- Running a static-site bundle built before 3 October 2026 with the file
server's command. Released again, such a bundle fails its readiness
check. - The workflow schema's
on: workItemtrigger, which did nothing. Stored
workflows that use${{workItem.*}}still expand.
Migration 163 drops the tables and columns only these features used,
rewrites old backup items, need states and deployment readiness into their
current form, and revokes live grants of the removed permissions (the
revoked rows are kept).
Supported and experimental
- Workflow options are checked when a workflow is saved. An option a
step does not take is refused by name, with the ones it does take.
Before, an unknown option was dropped:minApprovals: 2on an approval
saved, and one vote passed it (the option isquorum). Stored workflows
keep running unchanged. - Packs and guidance blocks may state
apiVersion: apptown.dev/v1, as
workflows can; any other version is refused. - The compatibility guide lists what is Supported in 1.0 and what is
Experimental, with what each Experimental item lacks. Experimental items
say so at the start of their description: thejava-spring,
node-fullstack,wordpress-bedrock,dotnet,rust-service,godot-3d
andvideo-gamepacks; theredisandllmneeds; the Portainer, App
Platform and bucket website targets; theresearch,excavateand
product-specworkflows; and the customer feedback integration. - Newly experimental: the MCP tools at
/mcp/user(a 1.x release may
change them, and its notes say what changed),get_evaland
get_what_if, the backup-set manifest, approvals given in advance
(inAdvance), and bareapptown release <slug>, which releases to
Portainer. - Newly stated in "What 1.0 promises": a field's listed values (a state,
an outcome) may gain values; every core command exceptexecutingtakes
--json; for the MCP tools, the names, required arguments and
descriptions are promised, not the fields of an answer; theshcheck
contract (a read-only copy of the project, no network, at most 60
seconds, exit 0 conforms, 1 is a finding, anything else is "could not
assess"); a pack's toolchain is a startermise.toml, not pinned by the
pack version; the integration variables an app gets; and/_apptown/
belongs to AppTown on every app. apptown helplists the commands promised through 1.x first, now
includingapptown executing, and the rest under "not promised in 1.x".-agent-executor localand-host-scriptssay in their help that they
are experimental.
Upgrading from RC5
There is no supported upgrade from a release candidate. RC6 is for new
installs. The code that moved an install and its projects from the forge
names (apptown upgrade) was removed before this release, once the
maintainers' two installations had been moved.
An RC5 install cannot simply be started on RC6:
- AppTown reads no
FORGE_*setting, anddb.envmust already use the
APPTOWN_DB_*keys. - Apps get only the
APPTOWN_*names and/_apptown/. - Projects'
.forge/folders are not moved to.apptown/. - Sessions, MCP tokens, invite links and Git tickets made before the rename
stop working.
The database itself does upgrade: RC6's migrations run over an RC5
database, and the upgrade tests check it.
For a new install, follow Running AppTown. For later upgrades, the
upgrading guide is unchanged: check nothing is executing, stop AppTown,
take the two copies, replace the binaries and start.
Database migrations
RC6 has thirteen, 153 to 165. 153: each backup check records the item it
checked. 154: stored names the rename changed (backup sets on AppTown's own
disk are apptown-disk, complaints about the platform are about
apptown). 155: the stock platform pack is apptown. 156: a what-if
records whether it moves each project's other workflows to their newest
versions. 157: a what-if records the other pack versions it moves with its
own. 158: each deployment records the prefix of the names it gives things
outside AppTown. 159: a change can be closed as shipped with a later
change. 160: stored category values forge become apptown. 161: tokens
made before purposes are revoked, and a token without a purpose must be a
revoked one. 162: deployments are named on their hosts by their key, and
the prefix is kept only for one not yet moved. 163: the removed features'
tables and columns are dropped, and old deployment records take their
current shape. 164: pack versions that named a policy without its
definition get the library's definition. 165: a change left proposed is
abandoned.
HTTP API changes
Routes added:
POST /api/v1/projects/{slug}/deployments/{name}/move-names: move a
deployment made before RC6 to the new names (apptown move-names).POST /api/v1/changes/{id}/recheck: run a landing's failed gates again
(apptown recheck).GET /api/v1/conformance/what-ifs: the list of what-ifs.GET /api/v1/projects/{slug}/adoption/in-advance: what a yes given in
advance would accept.GET /tls/ask: a TLS proxy on the same machine, such as the one-server
compose file's Caddy, asks whether a name may have a certificate. It
answers only callers on the same machine, and only for names AppTown
records.
Routes removed:
- Project export:
GET /api/v1/projects/{slug}/export. - The backlog:
POST /api/v1/changes/{id}/start. - The ownership inspection:
GET /api/v1/ownership/inspection,
POST /api/v1/ownership/approvals. - The change catalogue's editing:
POST /api/v1/catalog,
PATCH /api/v1/catalog/{name},POST /api/v1/catalog-promote/{name}. - Restored copies:
POST .../restored-copies/{id}/openand.../extend. - Rechecking a stage:
POST /api/v1/runs/{id}/recheck. - Webhook triggers:
POST /api/v1/hooks/{slug}/{workflow}. - Drafting and simple changes:
POST /api/v1/assist/workflow,
POST /api/v1/projects/{slug}/changes/simple. - Feature switches:
GET /api/v1/features,
POST /api/v1/conformance/history/clear. - Routes nothing called:
POST /api/v1/packs/pick,
POST /api/v1/projects/{slug}/deletion/revoke,
GET /api/v1/projects/{slug}/workflows/{name}/history,
DELETE /api/v1/projects/{slug}/members/{grantee},
GET /api/v1/secrets/stores,POST /api/v1/users/{name}/rename,
GETandPOST /api/v1/projects/{slug}/extensions,
POST /api/v1/projects/{slug}/owner, andGET /items/{id}.
Responses changed:
- The AppTown rename: request and response headers are
X-AppTown-*
(X-AppTown-Actor,X-AppTown-Deny-Code,X-AppTown-CLI-Protocol,
X-AppTown-Version, …); fields namedforgeareapptown(capacity's
figures and counts, a backup set's manifest,apptown version --json),
forgeFaultisapptownFault, the capacity tenant and a rehearsal's
unavailability reason sayapptown(on-apptown-disk), a complaint's
aboutisapptown, and the OpenVEX document names
apptown:project/<slug>. The API description's extension keys are
x-apptown-*. A caller that sends the oldX-Forge-*headers is served
as one that states no protocol. - Restoring a backup set
(POST /api/v1/projects/{slug}/deployments/{name}/backups/{id}/restore)
answers202with the operation instead of aRestoreResult. The
restore's outcome is the operation'sresult.restore. - Memory in requests and responses is in
Mi/Gi: a deployment's memory
override refuses a bare512M, and resource views show512Mi. - A request for a proposed change is refused.
- A project's slug cannot be changed.
- A request that passes a git push larger than
-import-bundle-max-bytes
gets HTTP 413. - Adopting a version (
POST /api/v1/projects/{slug}/adoption/adopt) needs
project:select-way-of-working, as applying a pack does, instead of
project:configure. GET /api/v1/packsnow describes its answer, a list ofPackView; the
CLI reads it. The answer itself did not change.
Fields and values removed:
- A new change's request (
POST /api/v1/projects/{slug}/changes) has no
propose, and a change'sstateis neverproposed. - A deployment has no
expiresAt(restored copies are no longer extended),
and itsreadinessis neverneeds-reconcile. - A run (
GET /api/v1/runs/{id}) has noneedsRevision. - A check's placement has no
role(the check-only worker is removed).
Request and response shapes gained optional fields:
- A named release (
POST /api/v1/projects/{slug}/deployments/{name}/deploy)
and an intranet release (POST /api/v1/projects/{slug}/release) take
acceptUncopiedData.apptown release --accept-uncopied-datasends it. - A named release also takes
acceptUncheckedCopy, which
apptown release --accept-unchecked-copysends. - A backup item has
bucketwhen it is an App Platform bucket. - The need catalogue (
GET /api/v1/dependencies) gainsprovides,
credentials,generate,integrationandwithdrawn; a need'slocal
block gainsentrypoint,configAtStart,keepsImageandstepEnv; a
copy gainsrunIn. Itscloudentries loseterraform,injectand
cluster. - A tests step's evidence carries
testCountsandskippedTests, or
testReportsaying why the counts are not known. POST /api/v1/dev-composereturns wired need values in its process-mode
env.- A change (
GET /api/v1/changes/{id}) gainshead, the change's current
commit;committedDiff.shipped, the release a change with no code of its
own put live and the earlier release it was compared with; andevidence.inAdvance, a yes given in advance on an adoption.
The rows of what a change adds gainbaseUnread, saying why main's side could
not be read when the change's could.
The CLI protocol (1) and the worker protocol (2) are unchanged; their
headers are renamed. A worker now refuses a request that does not say which
protocol AppTown speaks.
Deprecations
These are removals before 1.0, so no minor release comes first.
- The
forgenames are gone, with no overlap. Apps get noFORGE_*
variables,__FORGE_ENV__or/_forge/files.apptowndand the CLI
read noFORGE_*settings, and the CLI does not read
~/.config/forge/credentials. Old invite links, Git tickets, MCP tokens
and sessions stop working. - Five
apptowndflags are removed (-agent-model,
-agent-concurrency,-errors-url,-mirror-base,
-portainer-environment), andAPPTOWN_REAP=onis refused (write
true). See "Running AppTown". - The features under "Removed" are gone, with their routes and flags.
- A bare
MorGfor memory is refused in a version-2 contract. Write
MiorGi. A version-1 contract is still read as before. - Stock that is no longer shipped stops being offered. A stock
workflow, guidance block or policy this release no longer ships leaves the
libraries and the workflow choices of projects that never selected it, and
a stock pack it no longer ships is turned off. A project that already uses
one keeps it, and its Working page shows "No longer shipped" beside it. - SQLite is no longer a stock option. The
data/sqlite-everywhere
guidance is withdrawn. Projects that adopted it keep their version; move
the app's data to thepostgresneed and then remove the block.
data/networked-databasegets a new version whose text no longer offers
SQLite. - The
dynamodbneed is removed. No stock pack used it, its emulator
kept its data in memory, and no target but a Docker host could run it. Use
Postgres (JSON columns) or Redis. - The
ssoandtelemetryneeds are removed. They were never
fulfilled. Sign-in and telemetry values come from an integration attached
under Settings › Integrations, which is unchanged. - A contract that declares
dynamodb,ssoortelemetryunderneeds:is
refused as asking for an unknown need.errorsunderneeds:is refused
too; attach it as an integration. - Redis's
REDIS_HOSTandREDIS_PORTare withdrawn. ReadREDIS_URL,
which can carry the password. - A
passwordunderneeds.postgresorneeds.mariadbis refused.
AppTown sets the password. - Removed workflows and policy.
build,change-requestand
patch-dependencies(useimplement,quick-changeand
dependency-uplift), and themr-requires-secrets-scanpolicy. No project
had them installed; past runs keep the definitions they ran under. - Unbuilt cloud promises are removed. The need catalogue loses the AWS
blocks inpostgresandredisandpostgres's DigitalOceancluster
name, none of which were built. - The "Kubernetes cluster, not built yet" tile is gone from the
add-a-target page.