Coordinate changes that touch both the aweb OSS repo and the hosted ac repo. OSS lands first; the hosted repository owns dependency derivation and deployment.
Installs into .claude/skills of the current project.
Are you the author of Cross Repo Change?
Add the live security badge to your README. It updates with every re-scan.
[](https://www.skillsdirectory.com/skills/awebai-cross-repo-change)
---
name: cross-repo-change
description: Coordinate changes that touch both the aweb OSS repo and the hosted ac repo. OSS lands first; the hosted repository owns dependency derivation and deployment.
---
# Cross-repo change coordination
Changes that affect both aweb (OSS) and ac (hosted SaaS) must be
coordinated carefully because ac embeds aweb as a PyPI package.
## Read this first: shippability
**A released client is a permanent constraint.** Once a client that
sends X is in the field, the server must accept X until you can prove
nothing sends it.
Everything below about atomic deploys applies to **aweb ↔ ac only**. Every
other consumer — the channel plugin, pi, the `aw` CLI, self-hosted servers —
updates on its own schedule. A running agent
keeps its loaded module until the process **restarts**, which for a
long-lived agent may be never.
**Default: additive only.** You may ADD an accepted shape. You may NOT:
- remove an accepted shape,
- make an optional field required,
- reject a shape that is in the field,
- narrow a type or add a stricter validator to an existing field.
**The only exception:** you may narrow a contract if you can NAME every
consumer and show each deploys **atomically** with this change — same
image, same deploy, same instant. "We will release the client right
after" is not atomic. Put the justification in the commit message.
Today exactly one boundary qualifies: aweb ↔ ac.
**Removal is a separate, later change.** Remove support for an old shape
only after MEASURING that nothing sends it. If you cannot measure it,
you cannot remove it.
**Before merge, answer:** *what is deployed today, and does this still
work against it?* Check against PUBLISHED ARTIFACTS — `npm pack` the
tarball and read the shipped bundle, or read the released tag — never
against your own source. Your source and the published client disagree;
that disagreement is the entire risk.
Why this section exists: on 2026-07-26 a chat mark-read change made a new
field required and explicitly rejected the old one. Every published client
sent the old field, so deploying it would have broken every client in the
world. It was faithful to the anti-pattern below, which is correct for the
cloud boundary and catastrophic for clients. The process was not ignored —
it was followed.
## Principle (aweb ↔ ac only)
The cloud imports aweb. Both deploy in the same Docker image.
There is no transition period — when the cloud pins a new aweb
version, both the old and new code deploy atomically.
This is the ONLY boundary with that property. Do not generalise it.
## Sequence
1. **Design** — agree on the contract change between OSS and cloud.
Identify which side goes first.
2. **OSS first** — land the OSS change on aweb main after the relevant focused
tests pass.
3. **Release OSS** — run `make release-candidate TAGS='...'` in aweb, then push
each resulting tag separately. `docs/release.md` is authoritative. Wait for
the exact package versions to be public.
4. **Cloud pins** — update and review `backend/pyproject.toml` and
`backend/uv.lock` to the exact public OSS versions on AC `main`.
5. **Cloud candidate** — land the cloud-side source change on AC `main`, then
run `make release-candidate VERSION=X.Y.Z`. Push the resulting `vX.Y.Z` tag;
AC never publishes OSS artifacts.
6. **Verify** — cloud tests pass against the real aweb package (not
editable/sibling source).
## Anti-patterns
- Do NOT land the cloud change before the OSS release. The cloud
CI will fail on import errors.
- Do NOT use editable/sibling source installs as a permanent
workaround. They mask version pinning issues.
- Do NOT accept both old and new formats "during transition" when
both sides deploy atomically. Pick one format. **This applies to
aweb ↔ ac and nowhere else.** Before invoking it, confirm
every consumer of the contract deploys in that same image. If any
consumer is a published client — channel, pi, `aw` — or a
self-hosted server, the rule INVERTS: accept both, prefer the new
one, and remove the old only after measuring. See "Read this
first: shippability".
- Do NOT change a contract without enumerating what currently sends
it. For the channel that check is small — its entire write surface
is two calls, one of which has no body — so there is no excuse for
skipping it.
## Hosted schema mirrors
The `ac` repository maintains its own copy of the OSS schemas. The cloud's
`migration_paths.py` points at `backend/src/aweb_cloud/migrations/aweb/`
and `migrations/server/` — NOT at the OSS package's migrations in the
installed `.venv`. So when an OSS release adds or alters a schema the
cloud uses, the cloud needs a paired mirror migration with a matching
ALTER/CREATE.
The migrations to mirror can live in DIFFERENT OSS tree subdirectories
within the same release. Easy to miss the second one when walking commit
by commit:
- `awid/src/awid_service/migrations/*.sql` → mirror in cloud as
`migrations/aweb/`.
- `server/src/aweb/migrations/aweb/*.sql` → also mirror in cloud as
`migrations/aweb/` (same target dir, different OSS source dir).
When reviewing a cross-repo bundle, grep ALL OSS migration trees touched
in the bundle, not just the first one you find. Pattern-blindness on the
second mirror is the failure mode.
Each mirror file should be a one-statement ALTER/CREATE matching the OSS
content, with a header comment naming the OSS source path so the lineage
is explicit.
## Example: aweb-aaje (proxy auth team_id format)
1. OSS: changed X-Team-ID validation from UUID to colon-form,
deleted _resolve_proxy_team_id (cde8889, 0fbe3d9, 78794ff)
2. Released: aweb 1.10.1
3. Hosted repo: pinned 1.10.1 and changed the bridge to send colon-form
(2761d0a5, 1f6e4797)
4. Both deploy together in the cloud Docker image
## Notes
- The hosted `ac` repo is cloned at `../ac` relative to the aweb
workspace.
- Ownership and review routing live in the active team instructions
and `aw workspace status`; do not rely on names written here.