{"id":50298103,"url":"https://github.com/scitrera/aether","last_synced_at":"2026-05-28T10:31:02.626Z","repository":{"id":357493091,"uuid":"1199924906","full_name":"scitrera/aether","owner":"scitrera","description":"AI Agent Rapid Development Fabric","archived":false,"fork":false,"pushed_at":"2026-05-22T04:17:43.000Z","size":3916,"stargazers_count":2,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-05-22T11:39:26.577Z","etag":null,"topics":["acl","agentic-ai","ai","durable-execution","grpc","mtls"],"latest_commit_sha":null,"homepage":"https://aetherlayer.ai","language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"other","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/scitrera.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":"CODE_OF_CONDUCT.md","threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":"SECURITY.md","support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-04-02T21:15:56.000Z","updated_at":"2026-05-22T04:17:47.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/scitrera/aether","commit_stats":null,"previous_names":["scitrera/aether"],"tags_count":3,"template":false,"template_full_name":null,"purl":"pkg:github/scitrera/aether","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/scitrera%2Faether","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/scitrera%2Faether/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/scitrera%2Faether/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/scitrera%2Faether/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/scitrera","download_url":"https://codeload.github.com/scitrera/aether/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/scitrera%2Faether/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":33605377,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-05-28T02:00:06.440Z","response_time":99,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["acl","agentic-ai","ai","durable-execution","grpc","mtls"],"created_at":"2026-05-28T10:30:59.275Z","updated_at":"2026-05-28T10:31:02.619Z","avatar_url":"https://github.com/scitrera.png","language":"Go","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Aether (Agent Fabric)\n\n**Aether is the connective tissue for multi-agent systems.** It is the substrate that long-running agents, finite\ntasks, human users, workflow engines, and orchestrators all plug into with typed identity, enforced routing\npermissions, durable task lifecycles, and on-demand compute, all with a clear audit trail and served over a single bidirectional gRPC stream per\nparticipant.\n\nIt is *not* a general-purpose message bus, a workflow engine, or an RPC framework. It is what those tools don't give\nyou on their own: a fabric where every participant is a known, addressable, authorized identity, where messages to\noffline agents lazily spin up the right compute, and where a task can pause, hibernate, request elevated authority\n(\"sudo\"), or be reclaimed by another worker without the surrounding application code knowing any of those mechanics\nexist. (Ok but then yes... it is also all those things)\n\n### Deployment tiers\n\nA single protocol surface, served by three different runtime shapes — pick the one that matches your scale and\ndurability needs:\n\n1. **AetherLite (local mode)** — single binary, embedded SQLite + Badger, no external dependencies. Dev, edge,\n   single-tenant self-hosted.\n2. **AetherLite (clustered, NATS JetStream)** — same binary, embedded NATS JetStream replaces in-process state and\n   adds cross-node messaging. Scales from 1-node test through 2-node async/sync replication to 3+ node quorum HA via\n   config only — no code changes.\n3. **Aether (full distributed stack)** — separate `gateway` binary backed by PostgreSQL (tasks, audit, ACL,\n   registry), Redis (session locks, KV, checkpoints), and RabbitMQ Streams (messaging backbone). Stateless gateway\n   replicas behind a load balancer; the original production deployment shape.\n\nAll three tiers serve the same wire protocol and SDKs (Go, Python, TypeScript).\n\nBuilt by [scitrera.ai](https://scitrera.ai).\n\n## Key Features\n\n- **Connection = Lock = Heartbeat** — An active gRPC stream serves simultaneously as the distributed lock for an\n  identity and its liveness proof. No separate heartbeat API is needed.\n- **Bidirectional Streaming** — A single `rpc Connect` stream multiplexes all client-server communication: messages, KV\n  operations, config snapshots, and signals.\n- **Distributed Session Management** — Exclusive identity locks with automatic expiry via the configured state backend\n  ensure only one connection per identity at any time.\n- **Hierarchical KV Store** — Namespace-scoped configuration with global, workspace, user, and user-workspace scopes.\n  Config is pushed to connecting clients as a baseline snapshot.\n- **First Class Access Control** — Access control is fundamentally baked into every layer which (1) enforces security\n    even preventing message sending/routing/receipt based on ACL rules as well as throughout KV, orchestration, etc and\n    (2) benefits applications and agent design by handling one of the more critical and error-prone parts of enterprise\n    development for you.\n- **Workspaces** — Built-in support for \"workspaces\" which are logical namespaces for agent identities, messages, and KV. \n  By default, workspaces are isolated but ACL rules allow cross-workspace messaging and KV if configured. \n  Applications can use workspaces to organize data and enforce access control.\n- **Intent-Based Message Routing** — SDKs provide helpers for topics to enable developers to focus on intent (e.g. send \n  message to some other agent, etc.) rather than the mechanics of topics and fan-in/out targeting. The SDKs and gateway \n  handle logistics for prefix-driven routing with per-principal permission enforcement.\n- **Orchestration / Lazy Loading** — When a message targets an offline agent or task, the gateway enqueues the message\n  and signals the responsible orchestrator to spin up compute.\n- **Built-in Workflow Engine** — Both **DAG-based** workflows (declarative graphs with typed inputs/outputs,\n  expression-driven edges, and conditional branching) and **event-driven** workflows (react to messages, task\n  lifecycle transitions, and KV changes) are first-class. Single-leader execution per workflow ensures consistency\n  without sacrificing the gateway's stateless scaling story; persistent state survives gateway restarts.\n- **Horizontal Scaling** — Stateless gateway instances share state through the configured state and messaging\n  backends, enabling multi-node deployments either on the JetStream-clustered AetherLite path or on the full\n  Redis + RabbitMQ + PostgreSQL stack.\n- **Progress Updates** — A built-in topic schema and message type for handling progress updates on tasks.\n- **Audit Logging** — Configurable event capture (connection, auth, message, KV, admin, ACL) with batched writes and\n  retention policies. By default, everything is captured in audit logs, but you control it.\n\n## Architecture\n\nAether is intentionally narrow in scope: it does **not** execute user code or internal workflows. It routes messages\nbetween external participants and manages durable state including task execution.\n\n### Core Components\n\nThe table below describes each component's responsibility. The backing implementation varies by deployment tier\n(in-process / Badger for Lite, JetStream KV+Stream for clustered AetherLite, Redis+RabbitMQ+PostgreSQL for the full\nstack).\n\n| Component            | Location                       | Responsibility                                                                       |\n|----------------------|--------------------------------|--------------------------------------------------------------------------------------|\n| **Gateway Server**   | `internal/gateway/server.go`   | gRPC stream handling, auth, connection lifecycle, message routing, KV/checkpoint ops |\n| **Router**           | `internal/router/router.go`    | Topic-to-stream mapping, producer pool management, shared consumer fan-out           |\n| **Session Registry** | `internal/state/session.go`    | Distributed identity locks with TTL, active session tracking                         |\n| **KV Store**         | `internal/kv/store.go`         | Hierarchical config store (global/workspace/user/user-workspace scopes)              |\n| **Checkpoint Store** | `internal/checkpoint/store.go` | Persistent state checkpointing for agents/tasks                                      |\n| **Task Store**       | `pkg/tasks/store.go`           | Task lifecycle management (pause/resume/hibernate/wake, dependencies, deadlines)     |\n| **ACL Service**      | `internal/acl/service.go`      | RBAC with delegation chains, authority requests, and workspace access enforcement    |\n| **Orchestration**    | `internal/orchestration/`      | Task dispatch and claim-based delivery; lazy-loaded compute via Orchestrators        |\n| **Workflow Engine**  | `internal/workflow/`           | DAG-based and event-driven workflows: scheduler, state machine, single-leader executor, expression evaluation |\n| **Identity Model**   | `pkg/models/identity.go`       | Eight principal types, topic address derivation via `ToTopic()`                      |\n\n### Connection Flow\n\n```\nClient                         Gateway                        Redis / RabbitMQ\n  |                               |                                |\n  |-- InitConnection ------------\u003e|                                |\n  |                               |-- Authenticate (mTLS/OAuth) --\u003e|\n  |                               |-- AcquireLock (SetNX+TTL) ---\u003e|\n  |                               |\u003c- Lock granted ---------------|\n  |                               |-- ACL Check -----------------\u003e|\n  |                               |-- Quota Check + Increment ---\u003e|\n  |                               |-- Subscribe to topic(s) -----\u003e|\n  |\u003c-- ConnectionAck (sessionID) -|                                |\n  |\u003c-- ConfigSnapshot (KV) -------|                                |\n  |                               |                                |\n  |\u003c======= message loop ========\u003e|\u003c====== stream I/O ============\u003e|\n  |                               |                                |\n  |-- (disconnect) --------------\u003e|                                |\n  |                               |-- Unsubscribe ---------------\u003e|\n  |                               |-- ReleaseLock ---------------\u003e|\n  |                               |-- Decrement quota -----------\u003e|\n```\n\n## Quick Start\n\n### Option A: AetherLite — local mode (no external dependencies)\n\nAetherLite bundles the gateway and workflow server into a single binary backed by embedded SQLite and Badger.\nNo Redis, RabbitMQ, PostgreSQL, or NATS required.\n\n```bash\ncd server\ngo build -o aetherlite ./cmd/aetherlite\nAETHER_ALLOW_DEV_MODE=true ./aetherlite --dev --insecure-admin\n```\n\nState is persisted in `./aether-lite-data/`. gRPC on `:50051`, admin UI on `:31880`. See\n[`./docs/aetherlite.md`](./docs/aetherlite.md) for details.\n\n\u003e Production-ready for single-node deployments. No horizontal scaling, no cross-node messaging — data loss on\n\u003e hardware failure unless S3 backups are configured.\n\n### Option B: AetherLite — clustered mode (embedded NATS JetStream)\n\nSame `aetherlite` binary as Option A, but with `AETHERLITE_CLUSTER_MODE=true`. Embedded NATS server replaces the\nin-process state surfaces (locks, pins, KV, session registry, checkpoints, message routing, audit stream) with\nJetStream-backed equivalents. The same code paths are used at every scale — go from a 1-node test instance to a\n3-node quorum cluster purely by changing config.\n\n```bash\n# Single-node cluster (topology A2 — useful for testing cluster-mode features)\nAETHERLITE_CLUSTER_MODE=true ./aetherlite --dev --insecure-admin\n\n# 2-node async (topology B1) — primary + hot mirror, accepts 1–5s RPO on failover\nAETHERLITE_CLUSTER_MODE=true \\\nAETHERLITE_CLUSTER_PEERS=nats://replica:6222 \\\nAETHERLITE_HA_MODE=async \\\n./aetherlite\n\n# 3+ node quorum (topology C) — full HA, zero data loss\nAETHERLITE_CLUSTER_MODE=true \\\nAETHERLITE_CLUSTER_PEERS=nats://node2:6222,nats://node3:6222 \\\n./aetherlite\n```\n\nDocker Compose manifests for each topology live under\n[`server/deployments/docker-compose/`](server/deployments/docker-compose/)\n(`cluster-single.yaml`, `cluster.yaml`, `cluster-ha.yaml`).\n\nSee [`server/docs/aetherlite-clustering.md`](server/docs/aetherlite-clustering.md) for the full topology matrix:\nwhich backend stores each concern at each scale (identity locks, KV, audit log, task queue, registry, etc.),\nRPO/RTO targets, and S3 backup behavior.\n\n\u003e **Why use B over A?** Cross-node messaging, HA failover, and live cluster-mode feature surfaces (JetStream\n\u003e Watch-driven `PrefixIndex`, authority lifecycle events, replicated audit stream) — all without operating\n\u003e Redis, RabbitMQ, or PostgreSQL.\n\n### Option C: Full Aether (Redis + RabbitMQ + PostgreSQL)\n\nThe original distributed deployment: a separate `gateway` binary, stateless replicas behind a load balancer,\nstate in Redis (session locks, KV, checkpoints), task lifecycle / ACL / audit in PostgreSQL, and messages on\nRabbitMQ Streams.\n\n#### Prerequisites\n\n- Go 1.25+\n- Redis 7+ (or Valkey) — session registry and KV store\n- RabbitMQ 3.13+ with the Streams plugin — messaging backbone\n- PostgreSQL 16+ — task registry, orchestration profiles, audit log\n\n#### Start Development Dependencies\n\n```bash\n# RabbitMQ Streams (ports 55552 stream, 55672 AMQP, management UI on 15672)\n./scripts/docker_rmq_test.sh\n\n# Redis / Valkey\n./scripts/docker_valkey_test.sh\n```\n\n#### Build and Run\n\n```bash\n# Build\ngo build -o gateway ./cmd/gateway\n\n# Run with the default dev config\n./gateway --config configs/dev.yaml\n\n# Or run directly\ngo run ./cmd/gateway\n```\n\n#### Run Tests\n\n```bash\ngo test ./...                         # all packages\ngo test -v ./internal/gateway/...     # specific package, verbose\n```\n\n## Configuration\n\nThe gateway is configured via a YAML file. CLI flags override config-file values.\n\n```yaml\n# configs/dev.yaml (abbreviated)\ngateway:\n  port: 50051\n  gateway_id: \"gateway-dev-1\"\n\nadmin:\n  enabled: true\n  port: 31880\n\nauth:\n  modes: [ mtls, task_token, api_key ]\n  mtls:\n    required: false\n    mode: relaxed\n  oauth:\n    verify_signature: false   # disable JWT sig verification in dev\n\npostgres:\n  host: \"localhost\"\n  port: 55432\n  database: \"aether\"\n  user: \"aether\"\n  password: \"aether_dev\"\n\nredis:\n  cluster:\n    - \"localhost:56379\"\n    - \"localhost:56380\"\n    - \"localhost:56381\"\n\nrabbitmq:\n  stream_url: \"rabbitmq-stream://guest:guest@localhost:55552\"\n  amqp_url: \"amqp://guest:guest@localhost:55672/\"\n\naudit:\n  enabled: true\n  event_types: [ connection, auth, message, kv, admin, acl ]\n  retention_days: 90\n\nlog_level: \"info\"\n```\n\n### CLI Flags\n\n| Flag                                                                | Description                                            |\n|---------------------------------------------------------------------|--------------------------------------------------------|\n| `--config \u003cpath\u003e`                                                   | Path to YAML config file (default: `configs/dev.yaml`) |\n| `--port \u003cn\u003e`                                                        | gRPC server port (overrides config)                    |\n| `--tls`                                                             | Enable mTLS                                            |\n| `--cert-file`, `--key-file`, `--ca-file`                            | mTLS certificate paths                                 |\n| `--db-host`, `--db-port`, `--db-user`, `--db-password`, `--db-name` | PostgreSQL overrides                                   |\n| `--redis \u003chost:port\u003e`                                               | Redis address override                                 |\n| `--stream-url`                                                      | RabbitMQ Stream URL override                           |\n| `--amqp-url`                                                        | RabbitMQ AMQP URL override                             |\n| `--admin-port \u003cn\u003e`                                                  | Admin UI port override                                 |\n\n## Principal Types\n\nEvery connection authenticates as exactly one of eight principal types.\n\n| Type                | Uniqueness                  | Identity Fields                                     | Notes                                                                        |\n|---------------------|-----------------------------|-----------------------------------------------------|------------------------------------------------------------------------------|\n| **Agent**           | One connection per identity | `workspace` + `implementation` + `specifier`        | Long-running service                                                         |\n| **Unique Task**     | One connection per identity | `workspace` + `implementation` + `unique_specifier` | Named finite unit of work                                                    |\n| **Non-Unique Task** | Many connections allowed    | `workspace` + `implementation` (server assigns ID)  | Workers competing for tasks on a shared broadcast topic                      |\n| **User**            | One connection per window   | `user_id` + `window_id`                             | Multiple browser tabs allowed                                                |\n| **Workflow Engine** | One active connection       | N/A (Future: sharding)                              | Sole subscriber to `event.*` topics                                          |\n| **Metrics Bridge**  | One active connection       | N/A (Future: sharding)                              | Sole subscriber to `metric.*` topics; receive-only                           |\n| **Orchestrator**    | One per specifier           | `implementation` + `specifier`                      | Receives `TaskAssignment` messages to spin up compute                        |\n| **Service**         | One per specifier           | `implementation` + `specifier`                      | Cross-workspace HTTP-over-Aether proxy; addressable via `sv::{impl}::{spec}`   |\n| **Bridge**          | One per specifier           | `implementation` + `specifier`                      | Cross-workspace messaging integration; sends to any workspace subject to ACL |\n\n## Topic Schema\n\nMessages are routed by a structured topic prefix.\n\n| Prefix     | Target           | Format                                | Description                                           |\n|------------|------------------|---------------------------------------|-------------------------------------------------------|\n| `ag`       | Agent            | `ag::{workspace}::{impl}::{spec}`        | Specific agent instance                               |\n| `tu`       | Unique Task      | `tu::{workspace}::{impl}::{unique_spec}` | Named task instance                                   |\n| `ta`       | Assigned Task    | `ta::{workspace}::{impl}::{task_id}`     | Server-assigned non-unique task instance              |\n| `tb`       | Task Broadcast   | `tb::{workspace}::{impl}`               | Load-balancing topic; all workers of a type compete   |\n| `us`       | User (Window)    | `us::{user_id}::{window_id}`            | Specific browser window                               |\n| `uw`       | User (Workspace) | `uw::{user_id}::{workspace}`            | User scoped to a workspace                            |\n| `ga`       | Global Agents    | `ga::{workspace}`                      | Broadcast to all agents in a workspace                |\n| `gu`       | Global Users     | `gu::{workspace}`                      | Broadcast to all users in a workspace                 |\n| `pg`       | Progress         | `pg::{workspace}`                      | Progress updates with server-side recipient filtering |\n| `event.*`  | Workflow Engine  | `event.{workspace}`                   | Workflow Engine is the sole subscriber                |\n| `metric.*` | Metrics Bridge   | `metric.{workspace}`                  | Metrics Bridge is the sole subscriber                 |\n| `sv`       | Service          | `sv::{impl}::{spec}`                    | Cross-workspace service proxy endpoint                |\n| `br`       | Bridge           | `br::{impl}::{spec}`                    | Cross-workspace messaging bridge endpoint             |\n\n### Permission Matrix\n\n| Sender          | Can Send To                                           |\n|-----------------|-------------------------------------------------------|\n| Agent           | Agents, Tasks, Users, Broadcast Events, Metrics       |\n| Task            | Agents, Tasks, Users, Broadcast Events, Metrics       |\n| User            | Agents, Tasks, Users                                  |\n| Workflow Engine | Agents, Tasks, Users, Broadcast Events, Metrics       |\n| Metrics Bridge  | None (receive only)                                   |\n| Orchestrator    | Task/Agent topics only (status updates)               |\n| Service         | Any topic (cross-workspace); per-message ACL enforced |\n| Bridge          | Any topic in any workspace; per-message ACL enforced  |\n\n## gRPC API\n\nThe full API is defined in [`api/proto/aether.proto`](api/proto/aether.proto).\n\n```protobuf\nservice AetherGateway {\n  // Bidirectional stream. First message must be InitConnection.\n  rpc Connect (stream UpstreamMessage) returns (stream DownstreamMessage);\n}\n```\n\n**Upstream (client to server):** `InitConnection`, `SendMessage`, `SwitchWorkspace`, `KVOperation`,\n`CheckpointOperation`, `CreateTaskRequest`, `ProgressReport`, `TaskQuery`, `TaskOperation`\n\n**Downstream (server to client):** `ConnectionAck`, `IncomingMessage`, `ConfigSnapshot`, `Signal`, `ErrorResponse`,\n`KVResponse`, `CheckpointResponse`, `TaskAssignment`, `TaskQueryResponse`, `TaskOperationResponse`, `ProgressUpdate`\n\n**Message types:** `CHAT`, `CONTROL`, `TOOL_CALL`, `EVENT`, `METRIC`\n\nRegenerate Go bindings after proto changes:\n\n```bash\n./scripts/compilo_protos.sh\n```\n\n## Client SDKs\n\n- **Go SDK**: [`sdk/go/`](sdk/go) — full-featured SDK with typed clients for all eight principal types, sync/async KV \u0026\n  checkpoint helpers, reconnection with backoff, and TLS/mTLS support. See [`sdk/go/README.md`](sdk/go/README.md).\n- **Python SDK**: [`sdk/python-client/`](sdk/python-client) — sync and async clients with feature parity, including\n  orchestrator and multiprocess orchestrator implementations. See [\n  `sdk/python-client/README.md`](sdk/python-client/README.md).\n- **TypeScript SDK**: [`sdk/typescript/`](sdk/typescript) — Agent and User clients with gRPC transport, auto-reconnect,\n  KV operations, and typed error hierarchy. See [`sdk/typescript/README.md`](sdk/typescript/README.md).\n\n### Horizontal Scaling Notes\n\n**Option C (full Aether):**\n- All mutable state lives in Redis and PostgreSQL — gateway instances are stateless.\n- Redis `SetNX` locks guarantee identity uniqueness across all replicas.\n- RabbitMQ Streams preserve consumer offsets; clients reconnecting to a different instance experience no message loss\n  (at-least-once delivery).\n- Locks are TTL-backed; a crashed gateway's locks expire automatically so clients can reconnect to another instance.\n\n**Option B (AetherLite clustered):**\n- Identity locks, pins, sessions, KV, checkpoints, and registry live in JetStream KV with configurable replica counts\n  (R=1 standalone, R=2 quorum, R=3+ HA).\n- Topic message routing flows through JetStream Streams with consumer offset tracking — same at-least-once guarantee as\n  RabbitMQ Streams in Option C.\n- Task lifecycle, ACL, and audit have a hybrid model: SQLite per-node for fast reads, JetStream KV / CDC stream for\n  cross-node coordination.\n- Scale-up path is config-only: add `AETHERLITE_CLUSTER_PEERS`, restart, and JetStream forms a quorum across the new\n  node set.\n- See [`server/docs/aetherlite-clustering.md`](server/docs/aetherlite-clustering.md) for the per-topology backend matrix\n  and failure-mode analysis.\n\n## License\n\nCopyright 2025+ scitrera.ai\n\nLicensed under the Apache License, Version 2.0. See the [LICENSE](LICENSE) file for details.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fscitrera%2Faether","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fscitrera%2Faether","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fscitrera%2Faether/lists"}