All supported versions are declared in tools/versions.env. Run:
make toolsThe check is exact and fails with an actionable list when a tool is absent or
has drifted. The current foundation expects Go, Node.js, npm, Docker Compose, Docker Buildx, Terraform,
Yandex Cloud CLI (yc), YDB CLI, and Goose. Cloud tools are validated here even
though the first local process only needs Go and Docker.
| Tool | Pinned version | Installation source |
|---|---|---|
| Go | 1.26.8 | go.dev/dl |
| Node.js | 24.19.0 | nodejs.org downloads |
| npm | 11.17.0 | npm install --global npm@11.17.0 |
| Docker Compose | 5.3.1 | Docker Compose install |
| Docker Buildx | 0.36.0 | Docker Buildx install |
| Terraform | 1.15.5 | HashiCorp releases |
| Yandex Cloud CLI | 1.22.0 | Yandex Cloud CLI install |
| YDB CLI | 2.33.0 | YDB CLI downloads |
| Goose | 3.27.1 | Goose releases |
For Goose, the reproducible Go installation command is:
go install github.com/pressly/goose/v3/cmd/goose@v3.27.1The vendor installers for yc and YDB may install a newer release. Run
make tools afterward; update tools/versions.env in a reviewed change instead
of silently using mixed versions.
Do not use a checked-in file for credentials. .env.example contains safe
defaults and an empty token slot only. On macOS, a developer can place a token
in Keychain once:
security add-generic-password -a "$USER" -s sessionless.telegram-bot-token -wInject it into the process environment for the current shell:
export TELEGRAM_BOT_TOKEN="$(security find-generic-password -a "$USER" -s sessionless.telegram-bot-token -w)"On other systems, use the OS credential store or a password manager that can export into the child process environment. Never write service-account JSON or subscription credentials into this repository.
The normal Web BFF can use the existing attached scheduler admission path with
WEB_ATTACHED_EXECUTION_ENABLED=true and WEB_ATTACHED_RESOURCE_PINS containing
a JSON array of sessionlessharness.AttachedResourcePin values. Each entry pins
the tenant, owner, subscription resource, worker, enrollment generation,
capability and policy digests, and an explicit expiring harness-binding
template. The template has no run, attempt or placement digest; ingress fills
those from the canonical request. Configuration is bounded to 64 entries and
64 KiB, rejects unknown fields, and cannot silently fall back to managed work.
Enrollment rotation requires replacing the pin. Live worker authority is checked
before ingress and again by the existing atomic AdmitDispatch transaction.
ATTACHED_WORKER_CONTROL_ENABLED=true with an explicit
ATTACHED_WORKER_CONTROL_AUDIENCE mounts authenticated challenge, attach,
exchange, sealed-input and output-receipt routes in the normal control API.
This requires the existing YDB and Object Storage configuration, but not a
Telegram token or webhook secret. With both Telegram and attached control off,
the control API remains health-only. Both flags default to false; malformed or
partial enabled configuration fails startup.
Canonical context windows are retained and sealed using the same event/snapshot codecs as the managed worker. Materialization verifies the exact session, snapshot, event window, trigger, immutable references and size limits. Terminal publication uses a ready server-owned receipt, not caller-supplied completion material. This composition does not activate a real provider or grant a credential: the production sealed-input constructor remains credentialless. The credential-bearing provider proof uses only the integration-test adapter; real attached-provider activation remains the separately reviewed #133 workstream. It is required for the selected attached MVP path, independently of managed implementation. #176/#180 own the agent-harness minimum/design; #175 owns managed composition and #90/#92 its platform and rollout proof.
make web-ci
make generate
make test
make build
make integrationmake web-ci performs a lockfile-only npm ci, checks generated OpenAPI types
for drift, runs Prettier, ESLint, Svelte/TypeScript checks, unit/component tests,
and builds the static WebUI. The build is copied into the Go Web BFF embed tree
only after stale generated assets are removed. Node.js and npm are exact pins;
use make web-tools when only the Web toolchain needs validation. The separately
gated make web-browser-install installs pinned Chromium, and
make web-browser-test runs the Playwright end-to-end and axe accessibility
suites. CI adds Playwright's Linux system dependencies through the same target.
make test checks formatting, runs go vet, unit tests, and the race detector.
The repository-wide rules for deterministic clocks, isolation, cleanup,
diagnostics, repeated execution, and exact-commit CI evidence are in
testing-best-practices.md.
make build writes every component declared by the Makefile to .build/bin.
This includes the control plane, Web BFF, local fixtures, isolated worker, and
operator-only schema, reset, deployment-lock, and Web bootstrap commands. The
Makefile is the authoritative component inventory; documentation deliberately
does not duplicate a count that drifts as slices are added.
The #129 Phase-0 plan prepares
three 24-hour observation cohorts and their proposed limits. Run
make attached-worker-experiment-plan to print schedule bounds from the
canonical poller, and make attached-worker-experiment-test for the offline
validator and existing cadence regressions. The planner neither contacts a
control plane nor starts a worker; its result is always draft_not_authorized.
It is a development command, excluded from deployed component/release assets.
No measured cost or approved execution manifest is supplied by this target.
make resolves the repository's Git common directory and shares
GOCACHE and GOMODCACHE below .git/sessionless-go-cache across every
linked worktree. Go's build cache is content-addressed and safe for concurrent
Go commands; the module cache is also normally shared by the Go toolchain.
GOTMPDIR, .build/bin, and .build/dockerless stay inside each
worktree. They may contain in-progress files, commit-specific binaries, process
metadata, logs, and mutable service data and must not be shared.
Inspect the resolved paths with:
make go-cache-statusmake clean removes only the current worktree's .build. After all Go
commands in every linked worktree have stopped, make go-cache-clean removes
the default shared cache. The cleanup target refuses
SESSIONLESS_GO_CACHE_ROOT overrides (including those inside the Git common
directory) and symlinked cache roots; it never passes an override to its shell
cleanup command.
Existing checkout-local caches are not migrated automatically.
The fast make ci contract uses fake registry fixtures to verify immutable
publication failures and deterministic manifest/receipt separation. The real
container identity gate is intentionally separate because it performs ten cold
builds:
make image-reproducibility-testIt requires a running Docker daemon (Colima is supported), creates two
temporary digest-pinned BuildKit builders and a pinned loopback registry, builds
all five images twice from git archive HEAD, and compares config, diff-ID,
layer, and manifest identities. Cleanup removes only those uniquely named
temporary resources. CI runs this gate on every mirrored commit and retains the
second verified set for trusted-main publication.
The Go builder is the Docker Official Image golang:1.26.8-alpine, pinned to
OCI index sha256:ce864e7223ac17b1775e6fd0b4c0db580c2eb50e7953a427916379e4b92a1628.
The reviewed linux/amd64 child manifest is
sha256:6e5de3f5b9fb7e30b8bb2ffe8dcbcbdaa2990f0f31267456eabe83f870a623be,
published from docker-library/golang revision
f47489bcbda87966b421340c536f39a34d00b45f on 2026-09-01. These values are
recorded in build/images.env; make image-build-inputs-test rejects drift
between that image tag, its index provenance, tools/versions.env, go.mod,
and both Dockerfile defaults. Before its first build,
make image-reproducibility-test resolves the immutable index and rejects any
linux/amd64 child digest, source URL/revision, or image-version annotation
that differs from this reviewed record.
The bounded Codex App Server feasibility evidence, stable protocol subset, subscription-auth boundary, and still-open cloud/policy gates are documented in codex-subscription-worker.md. The selected integration surface, credential locality, and production gates are recorded in codex-integration-surface.md. That Phase A client is intentionally not wired into worker product state yet and never falls back to API-key billing.
The opt-in credential-free SDK/App Server/exec comparator, exact artifact provenance, sanitized aggregate schema, and explicit operator-consent boundary are in codex-surface-measurement.md. Its local Python environment and Codex binaries are research inputs and are not installed or invoked by normal developer or CI targets.
The current memory, tooling/MCP, attached-worker, AI-resource, metering, skills/automation, analytics, administration, and evaluation research is indexed in research/README.md. Those reports preserve evidence, alternatives, open questions, and proposed epic decomposition; they are not production contracts and do not close their research issues by themselves.
The implemented AW-01 owner-scoped identity, enrollment, generation, and deny-first revocation boundary is documented in attached-worker-identity.md. It is a domain and persistence contract only; it does not start a daemon or enable remote work.
The feature-disabled AW-03 bootstrap, immediate heartbeat transport, and presence persistence boundary is documented in attached-worker-transport.md. It does not claim reconnect, dispatch, long polling, or cloud wake-up.
The AW-05a Go daemon core, exact process-supervision contract, credential finalization order, and explicit unsupported-isolation boundary are documented in attached-worker-daemon.md. No developer command or production binary enables it yet.
The feature-disabled AW-05b OCI isolation profile and its explicit opt-in
real-engine matrix are documented in
attached-worker-oci.md. Run only against a reviewed,
explicit local engine endpoint with make attached-worker-oci-integration;
the ordinary test/CI path uses deterministic fake-client coverage.
The #132 local execution-stack assembly verifies the manifest-pinned Docker
CLI and harness artifacts, reconciles installation-owned OCI residue, and
composes the supervisor with the existing credential runner. It remains a
library boundary: attached-worker run does not call it and ordinary tests do
not contact an engine or provider.
The #137 service package staging and local control
adds a single lease-holding, still feature-disabled attached-worker serve
mode, a versioned permission-bound local status/doctor/drain/stop endpoint,
and exact launchd/systemd-user/rootless-container artifact plan/apply/rollback
receipts. make attached-worker-build builds only its native binary;
make attached-worker-package-test repeats its focused race/shuffle tests.
The opt-in make attached-worker-crash-integration builds that exact binary,
starts a test-owned synthetic/denied-credential service, kills its exact PID,
and verifies authenticated idle reconnect and lease retirement after restart.
make attached-worker-active-crash-integration forks the command dispatch in
a test binary with an injected clock, kills its active attempt owner, and
verifies that restart fences the non-idle checkpoint without replaying input.
The shipped binary retains the 15-minute minimum heartbeat interval; this
bounded test does not claim exact-binary active-crash coverage.
These fixtures need no provider credentials, Docker engine, OS service
registration, or cloud resources; ordinary make test skips both process-kill
fixtures.
The #79 make attached-worker-security-gate makes the two-owner transport
collision/secret-theft and cloned-identity reconnect checks, sealed-input
owner and credential denials,
HTTP client/poller response-loss fencing (no retry before reconciliation while
the peer continues), in-flight active-heartbeat settlement before terminal
reporting (or fail-closed cleanup timeout), protocol cancel/revoke fencing, CLI attempt-root/sentinel
checks, and both
crash/restart fixtures non-optional in make ci. The YDB CI job separately
runs make attached-worker-security-ydb-gate after migration: two distinct
owners in one tenant hold live claimed attempts under a deliberately colliding
worker ID and identity key, cross-owner sealed-input requests are denied, and
revoking one worker does not revoke the other's claim. Tagged releases also
require this exact-YDB gate before image publication. The YDB
target needs YDB_CONNECTION_STRING and credentials appropriate for the
already migrated test database. Neither gate enables real provider access.
The bounded #79/#166 gate is now closed; rollout-platform isolation and egress
remain #133's responsibility, not a new exhaustive #79 reopening condition.
CI also runs the focused joined-provider gate first, then the complete security
gate, in its own job with a newly started YDB Local alongside the full YDB
integration job. Both jobs must pass before runtime images are checked. The
provider-first order distinguishes failure on a fresh database from contention
or accumulated state after other integration cases without dropping coverage.
The tagged YDB gate includes TestAW07TwoActivatedProviderDaemonReceipts:
two activated daemons with colliding worker IDs use distinct test-only
subscription resources, credential generations, sealed inputs, credential
file mounts, receipt publication, and canonical terminal commits. For a
focused local diagnosis against migrated YDB, run
make attached-worker-joined-provider-ydb-gate. The fake provider issues no
real secret and the fake OCI client cannot execute a provider call.
The race-enabled joined YDB fixture uses a bounded 45-second per-exchange
budget for Docker-backed CI contention; shipped activation retains its
15-second operation and HTTP request timeouts.
The YDB gate also holds an owner-A terminal pending, revokes A, and verifies
that server-side materialization cannot turn the stale terminal evidence into
canonical run finalization while owner B remains authorized. The terminal
commit checks the current unrevoked owner-scoped worker and connection head in
the same transaction as the canonical write; an already committed terminal may
still be replayed idempotently.
The same gate reconnects an idle owner A while owner B retains a claimed job,
then proves that A's old bearer and generation stay fenced after A claims a
new job and after A is revoked; B's claim remains authorized throughout.
It also runs a joined TLS/YDB response-loss test: A's presence update commits
before its HTTP response is dropped, B progresses through the same control
plane, A requires reconciliation without replay, and revoking A does not
revoke B's sealed-input authority. This response-loss case alone is not the
two-daemon process, artifact, and provider-resource canary proof. The same
YDB gate now drives two claimed owners through the real HTTPS sealed-input
endpoint with separate context and artifact bytes. A's artifact read is held
across revocation: B remains readable, while A's post-read authority check
discards the held bytes. Cross-owner bearer borrowing is denied before any
object read. This sealed-input case alone does not prove the two-daemon
process or provider-resource boundaries.
The gate additionally repeats this held-read/revocation case with A and B as
separate test-owned OS client processes. Each child receives only an
owner-scoped HTTPS bearer and request, not inherited YDB or object-store
credentials: a cross-owner request cannot open an object, B reads its own
context and artifact while A is held, and A receives no material after
revocation. This covers the network/process boundary of sealed-input
delivery. By itself it is not an OS sandbox, credential-path,
activated-daemon OCI, or provider-resource proof.
The YDB gate also starts two separately activated daemon processes with
colliding worker locator and identity key against the same TLS/YDB control
plane. Each claims its own job and reads its own sealed context and artifact.
The synthetic OCI client is test-owned, so this proves transport-to-daemon
composition, exact owner-specific object reads, active A revocation without
stopping B, B cancellation-to-pending-terminal behavior, exact digest
fail-closure, and attempt-root/sentinel cleanup, not a real OCI or provider
resource boundary. The joined provider test above adds the test credential and
receipt path and completed the narrowed #79 gate. It does not claim a real
provider turn or an exhaustive rootless two-owner crash/reconnect matrix.
The receipt YDB gate separately pins distinct test-only provider resource IDs
and credential generations to the two owners. It rejects a successful receipt
without credential-release evidence, then proves an owner-A canonical receipt
and TerminalAck leave owner B's run untouched. This is a storage and protocol
authority check by itself. The joined provider test above now exercises the
activated test-only credential lifecycle. Actual rollout-platform egress and
isolation proof remains required by #133 before enabling real credentials.
The opt-in make attached-worker-native-integration exercises one exact
test-owned launchd or systemd user-service lifecycle. The separate opt-in
make attached-worker-rootless-integration runs the same lifecycle on Linux
against an already provisioned rootless Docker engine and preloaded immutable
execution-base image; the pinned CI gate provisions those inputs. See
attached-worker-packaging.md for the
registration/start/inspect/drain/stop contract and the #137 evidence.
Staging does not register or start an OS service or container. With no explicit
private activation profile, the foreground owner remains feature-disabled.
The opt-in #165 synthetic/denied-credential path is described in
attached-worker-packaging.md; it never enables
provider credentials or provider calls. #137/#165 are closed, including the
explicit activated rootless service path using narrowly configured host-engine
authority. The default unactivated rootless service remains offline. This
synthetic platform proof does not enable a real provider or remove #133's
rollout-specific egress/isolation gate.
The owner-facing AW-06a information architecture, read-model safety boundary, and control-action gates are documented in attached-worker-ux.md. WebUI and CLI implementations must consume that contract rather than deriving lifecycle state client-side.
The minimum #78/#170 private owner onboarding
uses make attached-worker-admin ARGS="..." with existing operator YDB
authority and typed confirmation, and make attached-worker-setup ARGS="..."
on the owner host. It retains a private pending identity before claim delivery,
registers one exact owner resource through production APIs, and completes local
state only from the matching receipt. No SQL fixture edits, service startup,
provider credentials or activation are implied. Eligibility remains unknown;
lost responses replay the same private grant/claim/rotation, not a new key.
The provider-neutral local credential binding, invocation handle, secure materialization, crash recovery, write-back, and deny-first revocation contract is documented in credential-lifecycle.md. Phase B0 is intentionally not activated in worker runtime until the selected profile's credential/isolation/rollout evidence passes. Telegram rollout #18 is not a managed-cloud MVP prerequisite.
The feature-disabled serverless authority, local isolation supervisor, and attested provider-egress/credential composition boundaries are documented in serverless-harness.md, serverless-isolation.md, serverless-egress.md, and the PR-03d Yandex substrate evidence plan. None registers a concrete cloud launcher, provider proxy, secret backend, or production route. The current MVP plan requires this managed cloud path without user-maintained compute alongside the required attached route. #176 research and #180 accepted design precede linked implementation of the bounded loop, compaction, useful constrained MCP and web search; #175 joins that harness into normal Web/control/worker flow, including admitted file/image processing. #90/#92 remain managed evidence gates; #129/#133 independently gate attached rollout. This scope correction does not enable runtime, authorize live calls or import ambient credentials.
The feature-disabled native direct OpenRouter reference backend pins one non-streaming Chat Completions request and strict observed-route response contract. Its tests use only a local fake boundary; no production HTTP boundary, key lookup, DNS request, or provider call is enabled.
The native provider composition accepts five explicit
pinned drivers and assembles their disabled registrations below the existing
exact-match harness registry. It performs no profile or executable discovery,
does not select a default backend, and is not wired into worker-runtime.
Run make provider-conformance for the credential-free provider registry
matrix. It performs vet plus repeated race-enabled tests over strict fixtures,
including the native feature-disabled Codex/OpenRouter, OpenCode/OpenRouter,
Pi/OpenRouter, and direct OpenRouter profiles plus their closed composition. It
reads no provider secret, starts no provider
process, performs no network call, and does not enable Codex, OpenCode, Pi, or
direct OpenRouter. A generic fake result reports native backend protocol as
skipped, even when its exact registry tuple passes.
Deployment-aware cleanup of those immutable registry images is a separate, fenced operational workflow. Its evidence bridge, dry-run/delete controls, and audit reports are documented in registry-gc.md. Never replace that workflow with an age-only or tag-count cleanup.
The bounded Apple Silicon source-build spike for YDB 25.3.1.25 reached a
conditional no-go. Do not replace the pinned Linux container with an
unvalidated native binary; see the native macOS YDB evidence and rerun
conditions.
Start and initialize the complete local stand:
make dev-up
curl http://127.0.0.1:8080/healthz
curl http://127.0.0.1:8081/healthzmake dev-up first starts pinned YDB Local, Silo (a MinIO fork), ElasticMQ, and the
deterministic Telegram fake. It waits for the infrastructure endpoints,
creates the local bucket, and applies the embedded YDB migrations. Only after
that schema barrier does it start the control API, queue-driven Telegram
sender, and queue-driven reconciler, then idempotently loads the synthetic Telegram
fixture. A fresh-volume YDB storage-pool initialization is retried without
starting schema consumers. Its YDB_MIGRATION_MAX_ATTEMPTS bound defaults to
60. Once HTTP monitoring is live, only the exact SDK failed to dial timeout
for loopback localhost, 127.0.0.1, or [::1] is also retryable; its
independent YDB_LOCAL_DIAL_MAX_ATTEMPTS bound defaults to 3 and covers raw or
slog-escaped quotes. Boot-storage markers take precedence. Generic deadlines,
remote endpoints, authentication/configuration errors, and DDL failures remain
fail-fast. Neither readiness path resets or deletes local data. The stand does
not require cloud credentials or a real Telegram token.
The worker is intentionally not kept alive by the default Compose profile. Local mode consumes at most one queue message and exits; cloud mode serves one bounded trigger-delivered batch per HTTP request. After an admitted local run is present:
make worker-onceThis starts the isolated worker-runtime profile, consumes at most one queue
message with the deterministic harness, stores checkpoints/artifacts/results,
then exits. An empty queue is a successful no-op. Scratch is a private tmpfs
and the container runs read-only as the distroless nonroot user.
The control API uses the YDB SDK single-connection balancer only inside the
Compose stand. This keeps the client on the Docker-resolvable ydb-local
endpoint instead of replacing it with YDB Local's host-facing discovery
address. Cloud deployments retain normal endpoint discovery and balancing.
Cloud preflight is Dockerless: it checks the cloud toolchain, billing gate and
Terraform configuration, not a local container engine. make terraform-ci
includes a credential-free regression with Docker absent from its command path.
It also checks Terraform's actual mocked, targeted Web plan: Web readiness must
wait for its registry, YDB, Object Storage, Lockbox, KMS and logging permissions,
without pulling publication/GC identity activation or unrelated runtime modules
into that graph. This is a dependency boundary, not permission to skip the
reviewed full deployment plan or to use targeting for ordinary deployments.
For release scope, see the WebUI-first MVP delivery plan. The MVP login selected in #168/#171 is Yandex ID OAuth, independent of Telegram and bot setup. The existing Telegram OIDC configuration remains the default for backward compatibility; selecting Yandex is explicit and never falls back to Telegram when credentials are absent or verification fails.
Set WEB_LOGIN_PROVIDER=yandex, YANDEX_LOGIN_CLIENT_ID to the registered
application's client ID, and inject YANDEX_LOGIN_CLIENT_SECRET from the
operator's credential store. WEB_BASE_URL is the exact public HTTPS origin;
register its /auth/login/callback URL with Yandex ID. Browser sign-in starts at
/auth/login/start. Request only the login:info permission, not email or avatar
access. The BFF uses these pinned production endpoints:
| Operation | Endpoint |
|---|---|
| Browser authorization | https://oauth.yandex.ru/authorize |
| Server-side code exchange | https://oauth.yandex.ru/token |
| Verified account information | https://login.yandex.ru/info?format=json |
This is Authorization Code OAuth with S256 PKCE, not OIDC: there is no Yandex
ID-token/JWKS/nonce verification path. The callback consumes a single-use,
browser-bound challenge with the selected provider and client binding. The BFF
exchanges the code privately, then calls the account API with the transient
access token in the Authorization: OAuth header. It accepts the JSON account
id only after client_id matches the configured application exactly. The
canonical identity is (yandex, id); email, login and display name never select
the user. Access/refresh tokens are not persisted or sent to the browser.
See the official code exchange
and account API contracts.
For cloud configuration, select Terraform web_login_provider = "yandex" and
set non-secret yandex_login_client_id. Load the secret with the existing
Web Lockbox loading workflow, using the matching
WEB_LOGIN_PROVIDER=yandex in the loader environment. The historical Lockbox
key oidc-client-secret stores the selected login secret; Terraform maps that
key to YANDEX_LOGIN_CLIENT_SECRET for Yandex or TELEGRAM_OIDC_CLIENT_SECRET
for Telegram. The key name does not make Yandex an OIDC provider. Never put the
client secret in Terraform variables/state, command arguments, checked-in
files, container images or logs.
Successful provider verification alone grants no tenant access. Pilot access requires a separate audited operator invitation or the existing cloud-development membership bootstrap for the canonical Sessionless user. A new identity without active membership cannot create a Web session, read another user's sessions or inherit quota. Equal Telegram/Yandex subject strings or emails are not account links. Explicit late linking of two proved accounts is post-MVP #172, not an MVP prerequisite.
For operator-assisted first access in cloud-dev, the existing
make web-bootstrap accepts optional WEB_BOOTSTRAP_EXTERNAL_PROVIDER=yandex
and WEB_BOOTSTRAP_EXTERNAL_SUBJECT with the operator-verified canonical numeric
Yandex account id (not its email or username). Supply the existing target
WEB_BOOTSTRAP_USER_ID, tenant, role, operator and reason as documented in the
bootstrap runbook. The typed confirmation becomes exactly
BOOTSTRAP <user> INTO <tenant> FOR yandex:<id>. Identity provisioning, membership
and its audit are one transaction. A subject owned by another user or a target
user with any different external identity is rejected; this is first-identity
provisioning, not a privileged shortcut for late linking. Without both optional
variables, the original bootstrap still requires an existing external identity.
Neither mode is available in production or accepts authority-bearing arguments.
YANDEX_LOGIN_AUTHORIZATION_ENDPOINT, YANDEX_LOGIN_TOKEN_ENDPOINT and
YANDEX_LOGIN_INFO_ENDPOINT overrides are accepted only for explicit loopback
fixtures when SESSIONLESS_ENVIRONMENT=local; they are not cloud proxy knobs.
Repository adapter/BFF/YDB/browser checks use synthetic accounts, not a real
provider login. Registered-client callback, Yandex endpoint reachability from
the deployed runtime and cloud browser smoke remain #34/#35 rollout evidence;
access to the Yandex Cloud console does not prove these endpoints reachable.
The selected-provider cloud smoke has a credential-free local entry point:
make cloud-web-smoke-testIt runs Node.js standard-library fixtures with fake curl/yc clients and checks
positive redirects, fail-closed configuration/response handling, redaction and
temporary-file cleanup. No Docker, YDB, cloud token or provider login is needed.
Repository CI runs the same target under the pinned Node.js version. The live
make cloud-web-smoke command requires separately approved cloud rollout
authority and explicit provider/public client configuration; see the
cloud runbook. A passing
login-start check does not prove an actual account callback or logged-in session.
The Web BFF and Telegram-shaped OIDC fixture are separate Go processes. The
fixture generates an ephemeral RS256 key at process start and refuses to start
unless SESSIONLESS_ENVIRONMENT=local. Production and cloud-development
processes selecting Telegram use its real issuer and receive the client secret
from the process environment or Lockbox. WEB_LOGIN_PROVIDER=telegram (or an
empty selector) preserves the legacy /auth/telegram/callback registration.
These fixture values do not configure Yandex login.
Build the binaries and run the credential-free repository checks:
make build
make testSecure browser cookies and exact-origin checks are never weakened for local
development. A manual browser flow therefore needs a local HTTPS reverse proxy
for https://web.localhost; the fixture endpoints may remain loopback HTTP and
are accepted only when the BFF itself runs in the local environment. See
web-bff.md for the route contract, environment variables,
bootstrap procedure, and threat boundary.
The Web canonical API additionally needs the existing Object Storage and
scheduler-wake queue coordinates. Local static S3 credentials use Silo in the
Compose stand and MinIO in the native dockerless stand;
cloud deployments set S3_IAM_METADATA_CREDENTIALS=true so both exact-object
operations and short-lived Yandex Object Storage capabilities use the workload
service account. SESSION_API_ID_HMAC_KEY must be at least 32 bytes and stable
across replicas because it derives upload, event, run, and dispatch identities.
WEB_MAX_UPLOAD_BYTES configures a positive upload limit (default 32 MiB), and
WEB_ALLOWED_MCP_SERVERS is an optional comma-separated allowlist copied into
Web-created jobs. WEB_OBJECT_STORAGE_ORIGIN is the exact browser-facing
origin of every direct upload/download capability and is added to CSP
connect-src; wildcards, paths, credentials, query strings, and non-HTTPS
origins are rejected. Only exact loopback HTTP is accepted when
SESSIONLESS_ENVIRONMENT=local (for example http://localhost:9000).
The direct upload sequence is intent, exact presigned PUT, commit, and then
message submission. Reusing an idempotency key retries the same logical
operation. Poll point runs with the returned ETag and delay headers, and use
after_sequence to project newly appended events. Do not persist capability
URLs or include them in logs, test snapshots, or browser analytics.
Run the adapter contracts and stop the stack:
make migrate-local
make local-integration
make e2e-local
make dev-downNormal stop/start preserves the YDB and Object Storage named volumes. ElasticMQ
and the Telegram fake are intentionally ephemeral transport fixtures. The
complete topology, endpoint table, local-only credentials, persistence test,
and Apple Silicon requirements are documented in
local-development-stand.md.
The e2e-local target starts the stand when needed, builds the isolated worker,
and executes the two-tenant product flow and recovery scenarios documented in
local-e2e.md.
After the YDB monitoring endpoint is ready, apply or inspect the schema:
export YDB_CONNECTION_STRING='grpc://127.0.0.1:2136/local?go_query_mode=scripting&go_fake_tx=scripting&go_query_bind=declare,numeric'
export YDB_ANONYMOUS_CREDENTIALS=1
make migrate-local
make migration-status
make partition-status
make ydb-integrationThe repository-owned migration binary embeds the SQL set and uses Goose as a
library. It adds a YDB-backed fenced lock, pre-execution checksums, one
idempotent DDL operation per file, and a forward-only production policy. See
migrations/ydb/README.md for crash repair and docs/ydb-state-store.md for
keys and transaction procedures.
make partition-status emits the live primary keys, partition settings, counts,
and contract drift as JSON. The bucketed ready/expiry expand/backfill/cutover
procedure is documented in
ydb-partitioning.md. make partition-backfill is a
deployment migration command, not a normal serving operation.
Local defaults use YDB_ANONYMOUS_CREDENTIALS=1. Cloud deployments use the
YDB environment credential chain and metadata credentials; do not place access
tokens in the connection string or command line.
To delete local Compose volumes, use the guarded command:
CONFIRM_LOCAL_RESET=sessionless-dev make dev-resetThe reset target affects only the fixed sessionless-dev Compose project. It
does not remove source directories or arbitrary Docker resources.
After a reviewed pre-production migration-baseline rebase, inspect and execute the separately guarded cloud-dev application-data reset:
make cloud-app-reset-plan
CONFIRM_CLOUD_APP_RESET='reset-sessionless-cloud-dev:<folder-id>:<artifact-bucket>' \
make cloud-app-resetThe command resolves its target from the selected Terraform state and preserves cloud infrastructure and unrelated object prefixes. The complete prerequisites, typed-confirmation derivation, and preservation boundary are documented in cloud-development.md. It is not a production migration or an ordinary deployment step.
Single-session archive, legal hold, bounded dry-run, and exact-object deletion are documented in session-lifecycle.md. Use only the Make targets in that runbook; the destructive command requires the digest of the resolved inventory and has no prefix-delete mode.
make images
make cimake ci includes the deterministic WebUI checks and static build before Go
verification and embedding. Go package commands use explicit repository package
roots so they never descend into web/node_modules; a layout guard fails if a
new project Go root is added without joining that inventory.
The control plane uses a small distroless runtime. The worker has a separate Dockerfile. Its deterministic harness validates lifecycle behavior now; a later decision can add OpenCode, Codex, Claude, Hermes, or another CLI without expanding the webhook/control-plane attack surface.
GitCode is the source of truth for branches and merge requests. Its push mirror
replicates every commit to github.com/urandon/sessionless, where GitHub Actions
runs make ci and make images for every mirrored branch or tag push. The
workflow is .github/workflows/ci.yml; a GitHub pull request is not required.
Ordinary branch and main CI never requests a GitHub OIDC token and never
contacts Yandex Container Registry. It still builds every runtime image twice
in independent clean rooms and uploads deterministic reproducibility evidence.
Publishing requires an explicit Publish runtime images workflow dispatch on
the exact current, converged GitCode/GitHub main SHA with a matching typed
confirmation. That separate job repeats the clean-room proof before requesting
OIDC and publishing the five immutable images. Publication creates a deployment
manifest; it does not deploy Terraform or a runtime revision. See
cloud-development.md.
When reviewing a GitCode merge request, match the GitHub Actions run to the GitCode head commit SHA. Automatic propagation of that status back into the GitCode merge-request UI is a separate integration; until it exists, this SHA check is the merge gate.
Publishing GitHub release artifacts back into GitCode is intentionally outside this CI workflow and tracked separately in issue #15. Branch CI does not receive a GitCode publication token.
Tag-driven GitHub Releases use a separate protected workflow and a dedicated Yandex identity. The tag formats, GitCode/GitHub provenance checks, environment gate, five-image asset contract, and same-tag retry procedure are documented in releases.md.
Cloud development environment procedures are documented in cloud-development.md. They use separate bootstrap and environment state, a folder-scoped external budget gate, immutable image digests with guarded commit-SHA tags, Lockbox payload injection outside Terraform, and blue/green API Gateway promotion.