Multi-Tenant Filesystem
Agor can partition tenant-owned files while keeping daemon state shared. This is intended for hosted deployments that resolve tenant identity from trusted authentication.
Configuration
multi_tenancy:
mode: required_from_auth
auth_claim: tenant_id
filesystem_isolation_enabled: true
tenants_base_folder: ~/.agor/tenants
uploads:
location: ~/.agor
max_age_days: 30
max_file_size_mb: 50filesystem_isolation_enabled defaults to false, preserving the existing
single-tenant layout. It is required when mode is required_from_auth; the
daemon rejects that mode without filesystem isolation.
tenants_base_folder may be absolute, such as /data/agor-tenants, or relative
to the daemon home (~/.agor). Its default is ~/.agor/tenants.
Filesystem layout
With filesystem isolation enabled, Agor creates directories lazily:
~/.agor/
tenants/
<tenant-id>/
repos/
worktrees/
uploads/
agor.db
config.yamluploads.location is a base storage location, not the final upload folder.
Agor owns and appends the tenant and uploads/ namespaces beneath it. Local
multi-tenant uploads therefore use
<location>/tenants/<tenant-id>/uploads/. In single-tenant mode they use
<location>/uploads/. max_age_days: 0 disables automatic expiry.
The base may also be an s3://bucket/prefix URI. The daemon uses the
AWS SDK credential and region provider chains, so configure credentials through
the workload identity (recommended), environment, or shared AWS configuration;
never embed credentials in the URI. Set the region through workload/shared
configuration or AWS_REGION.
S3 objects always use the same tenant-first partition. Operators provide only the bucket and optional base prefix; Agor manages everything below it:
<prefix>/tenants/<tenant-id>/uploads/objects/<handle-shard>/<upload-ref>Agor enforces tenant, branch, and session ownership before every read or delete.
The bucket policy should grant the daemon only the configured prefix. Agor does
not list or reconcile the bucket during upload requests. Configure S3 lifecycle
rules to expire objects after the configured retention and abort incomplete
multipart uploads. Failed transfers are also aborted directly by the uploader.
When max_age_days is zero, omit object expiration if permanent retention is
intended.
The daemon needs s3:GetObject, s3:PutObject, and s3:DeleteObject on the
configured object prefix, plus s3:AbortMultipartUpload for failed multipart
transfers. It does not require bucket-list permissions for normal upload
operation.
Expired upload maintenance
Upload expiry is enforced on access. S3 lifecycle rules are the normal Cloud mechanism for physical byte retention. Deployment operators may also remove a bounded batch of expired database metadata and its exact storage objects:
# Static/single-tenant deployment
agor local uploads cleanup --limit 500
# One tenant, or an explicit cross-tenant Cloud maintenance job
agor local uploads cleanup --tenant-id acme --limit 500
agor local uploads cleanup --all-tenants --limit 500Use --dry-run to count without deleting. This is a deployment-local command:
it reads the runtime database/configuration and uses local filesystem or AWS
credentials directly. It is not an authenticated, tenant-bound user API. The
S3 path performs exact-key operations and never lists or reconciles the bucket.
In the default single-tenant mode, paths remain unchanged:
~/.agor/
repos/
worktrees/
uploads/
agor.db
config.yamlUser homes and container mounts
Agor does not provision or relocate Unix user home directories as part of this setting. In Kubernetes or another container scheduler, user-home persistence is an executor provisioning responsibility. A deployment may mount a stable home for the Agor user together with only the authorized branch paths, using read-only or read-write mounts according to its RBAC policy.
The daemon upload root is not mounted into executors. When an agent needs an
upload, Agor streams an authorized copy into the executor-owned
.agor/session-staging/<session-id>/ directory inside the existing branch
workspace mount.
Migration
Enabling filesystem isolation does not move existing repositories, worktrees, or uploads. Configure it for a new multi-tenant deployment, or move existing tenant data into the target topology while the daemon is stopped. Database rows containing filesystem paths must agree with the resulting locations.
Moving and removing tenant data
To inspect, export, import, verify, or delete a single tenant’s database and filesystem data — for migration, backup and restore, or offboarding — see Tenant Data Portability.