eyvan 0.0.1__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- eyvan-0.0.1/PKG-INFO +305 -0
- eyvan-0.0.1/README.md +261 -0
- eyvan-0.0.1/eyvan/__init__.py +156 -0
- eyvan-0.0.1/eyvan/_dashboard/assets/LineChart-CcILbKnD.js +3 -0
- eyvan-0.0.1/eyvan/_dashboard/assets/LineChart-D1GxaB_c.css +1 -0
- eyvan-0.0.1/eyvan/_dashboard/assets/index-CUw1Ss_o.css +1 -0
- eyvan-0.0.1/eyvan/_dashboard/assets/index-aNA_h2N4.js +438 -0
- eyvan-0.0.1/eyvan/_dashboard/index.html +21 -0
- eyvan-0.0.1/eyvan/_internal/__init__.py +6 -0
- eyvan-0.0.1/eyvan/_internal/access_logging.py +308 -0
- eyvan-0.0.1/eyvan/_internal/build_identity.py +256 -0
- eyvan-0.0.1/eyvan/_internal/client_version.py +118 -0
- eyvan-0.0.1/eyvan/_internal/compat.py +11 -0
- eyvan-0.0.1/eyvan/_internal/correlation.py +68 -0
- eyvan-0.0.1/eyvan/_internal/correlation_ids.py +25 -0
- eyvan-0.0.1/eyvan/_internal/fleet_init_script.py +113 -0
- eyvan-0.0.1/eyvan/_internal/identifiers.py +17 -0
- eyvan-0.0.1/eyvan/_internal/json_types.py +55 -0
- eyvan-0.0.1/eyvan/_internal/network.py +34 -0
- eyvan-0.0.1/eyvan/_internal/observability.py +130 -0
- eyvan-0.0.1/eyvan/_internal/plane_tls.py +165 -0
- eyvan-0.0.1/eyvan/_internal/platform.py +79 -0
- eyvan-0.0.1/eyvan/_internal/ssh.py +491 -0
- eyvan-0.0.1/eyvan/_internal/subprocess_env.py +58 -0
- eyvan-0.0.1/eyvan/_internal/trace_context.py +55 -0
- eyvan-0.0.1/eyvan/_internal/training_metrics.py +111 -0
- eyvan-0.0.1/eyvan/_internal/workspace.py +613 -0
- eyvan-0.0.1/eyvan/_version.py +12 -0
- eyvan-0.0.1/eyvan/artifacts/__init__.py +388 -0
- eyvan-0.0.1/eyvan/artifacts/_capability_tokens.py +122 -0
- eyvan-0.0.1/eyvan/artifacts/managed.py +4145 -0
- eyvan-0.0.1/eyvan/artifacts/secret_capability.py +240 -0
- eyvan-0.0.1/eyvan/artifacts/transfers.py +172 -0
- eyvan-0.0.1/eyvan/artifacts/workload_capability.py +180 -0
- eyvan-0.0.1/eyvan/assistant_knowledge/__init__.py +923 -0
- eyvan-0.0.1/eyvan/assistant_knowledge/easydel_essentials.json +176 -0
- eyvan-0.0.1/eyvan/assistant_knowledge/easydel_trainers.json +12180 -0
- eyvan-0.0.1/eyvan/capacity/__init__.py +70 -0
- eyvan-0.0.1/eyvan/capacity/acquisition_backoff.py +265 -0
- eyvan-0.0.1/eyvan/capacity/audit.py +212 -0
- eyvan-0.0.1/eyvan/capacity/autoscale/__init__.py +120 -0
- eyvan-0.0.1/eyvan/capacity/autoscale/cache.py +957 -0
- eyvan-0.0.1/eyvan/capacity/autoscale/cluster_capacity.py +230 -0
- eyvan-0.0.1/eyvan/capacity/autoscale/compiler.py +324 -0
- eyvan-0.0.1/eyvan/capacity/autoscale/models.py +828 -0
- eyvan-0.0.1/eyvan/capacity/autoscale/pool_capacity.py +502 -0
- eyvan-0.0.1/eyvan/capacity/autoscale/profiles.py +179 -0
- eyvan-0.0.1/eyvan/capacity/autoscale/queue_admission.py +79 -0
- eyvan-0.0.1/eyvan/capacity/autoscale/service.py +336 -0
- eyvan-0.0.1/eyvan/capacity/conformance.py +706 -0
- eyvan-0.0.1/eyvan/capacity/data/accelerator_shapes.yaml +393 -0
- eyvan-0.0.1/eyvan/capacity/drivers/__init__.py +109 -0
- eyvan-0.0.1/eyvan/capacity/drivers/aws.py +513 -0
- eyvan-0.0.1/eyvan/capacity/drivers/azure.py +453 -0
- eyvan-0.0.1/eyvan/capacity/drivers/base.py +781 -0
- eyvan-0.0.1/eyvan/capacity/drivers/gcp.py +2237 -0
- eyvan-0.0.1/eyvan/capacity/drivers/gcp_attach.py +621 -0
- eyvan-0.0.1/eyvan/capacity/drivers/kubernetes.py +1918 -0
- eyvan-0.0.1/eyvan/capacity/drivers/local.py +260 -0
- eyvan-0.0.1/eyvan/capacity/drivers/manual.py +362 -0
- eyvan-0.0.1/eyvan/capacity/drivers/onprem_ssh.py +1396 -0
- eyvan-0.0.1/eyvan/capacity/drivers/registry.py +748 -0
- eyvan-0.0.1/eyvan/capacity/fleet_config.py +1026 -0
- eyvan-0.0.1/eyvan/capacity/fleet_state.py +1171 -0
- eyvan-0.0.1/eyvan/capacity/gcs_rest.py +200 -0
- eyvan-0.0.1/eyvan/capacity/hardware_catalog.py +648 -0
- eyvan-0.0.1/eyvan/capacity/planning.py +1653 -0
- eyvan-0.0.1/eyvan/capacity/providers/__init__.py +6 -0
- eyvan-0.0.1/eyvan/capacity/providers/aws/__init__.py +6 -0
- eyvan-0.0.1/eyvan/capacity/providers/aws/api.py +401 -0
- eyvan-0.0.1/eyvan/capacity/providers/aws/instances.py +199 -0
- eyvan-0.0.1/eyvan/capacity/providers/aws/signing.py +192 -0
- eyvan-0.0.1/eyvan/capacity/providers/azure/__init__.py +6 -0
- eyvan-0.0.1/eyvan/capacity/providers/azure/api.py +366 -0
- eyvan-0.0.1/eyvan/capacity/providers/azure/machines.py +206 -0
- eyvan-0.0.1/eyvan/capacity/providers/gcp/__init__.py +82 -0
- eyvan-0.0.1/eyvan/capacity/providers/gcp/accelerator_catalog.py +186 -0
- eyvan-0.0.1/eyvan/capacity/providers/gcp/compute_instances.py +1257 -0
- eyvan-0.0.1/eyvan/capacity/providers/gcp/native_worker_ingress.py +773 -0
- eyvan-0.0.1/eyvan/capacity/providers/gcp/queued_resources.py +1151 -0
- eyvan-0.0.1/eyvan/capacity/providers/gcp/quota_catalog.py +139 -0
- eyvan-0.0.1/eyvan/capacity/providers/gcp/quota_discovery.py +589 -0
- eyvan-0.0.1/eyvan/capacity/providers/gcp/quota_usage.py +355 -0
- eyvan-0.0.1/eyvan/capacity/providers/gcp/runtime/__init__.py +6 -0
- eyvan-0.0.1/eyvan/capacity/providers/gcp/runtime/bootstrap.py +527 -0
- eyvan-0.0.1/eyvan/capacity/providers/gcp/runtime/profile.py +637 -0
- eyvan-0.0.1/eyvan/capacity/providers/gcp/runtime/supervisor.py +1059 -0
- eyvan-0.0.1/eyvan/capacity/providers/gcp/tpu_discovery.py +362 -0
- eyvan-0.0.1/eyvan/capacity/providers/gcp/tpu_nodes.py +485 -0
- eyvan-0.0.1/eyvan/capacity/providers/gcp/tpu_ssh.py +231 -0
- eyvan-0.0.1/eyvan/capacity/providers/gcp/tpu_types.py +54 -0
- eyvan-0.0.1/eyvan/capacity/providers/gcp/tpu_zone_policy.py +54 -0
- eyvan-0.0.1/eyvan/capacity/providers/kubernetes/__init__.py +5 -0
- eyvan-0.0.1/eyvan/capacity/providers/kubernetes/api.py +578 -0
- eyvan-0.0.1/eyvan/capacity/providers/kubernetes/kueue.py +1123 -0
- eyvan-0.0.1/eyvan/capacity/providers/kubernetes/workers.py +392 -0
- eyvan-0.0.1/eyvan/capacity/stage_policy.py +90 -0
- eyvan-0.0.1/eyvan/config.py +909 -0
- eyvan-0.0.1/eyvan/domain/__init__.py +66 -0
- eyvan-0.0.1/eyvan/domain/accelerators.py +32 -0
- eyvan-0.0.1/eyvan/domain/availability.py +200 -0
- eyvan-0.0.1/eyvan/domain/carbon.py +202 -0
- eyvan-0.0.1/eyvan/domain/costing.py +114 -0
- eyvan-0.0.1/eyvan/domain/governance.py +279 -0
- eyvan-0.0.1/eyvan/domain/models.py +820 -0
- eyvan-0.0.1/eyvan/domain/prediction.py +177 -0
- eyvan-0.0.1/eyvan/domain/pricing.py +158 -0
- eyvan-0.0.1/eyvan/domain/scheduler.py +1358 -0
- eyvan-0.0.1/eyvan/domain/sizing.py +472 -0
- eyvan-0.0.1/eyvan/domain/spend.py +123 -0
- eyvan-0.0.1/eyvan/domain/tpu_chips.py +124 -0
- eyvan-0.0.1/eyvan/identity/__init__.py +90 -0
- eyvan-0.0.1/eyvan/identity/assistant_keys.py +81 -0
- eyvan-0.0.1/eyvan/identity/metadata.py +238 -0
- eyvan-0.0.1/eyvan/identity/mtls.py +412 -0
- eyvan-0.0.1/eyvan/identity/rotation.py +421 -0
- eyvan-0.0.1/eyvan/identity/team_secrets.py +158 -0
- eyvan-0.0.1/eyvan/py.typed +0 -0
- eyvan-0.0.1/eyvan/records.py +4528 -0
- eyvan-0.0.1/eyvan/sdk/__init__.py +15 -0
- eyvan-0.0.1/eyvan/sdk/cli.py +188 -0
- eyvan-0.0.1/eyvan/sdk/client/__init__.py +27 -0
- eyvan-0.0.1/eyvan/sdk/client/async_client.py +513 -0
- eyvan-0.0.1/eyvan/sdk/client/callables.py +816 -0
- eyvan-0.0.1/eyvan/sdk/client/endpoint.py +62 -0
- eyvan-0.0.1/eyvan/sdk/client/idempotency.py +28 -0
- eyvan-0.0.1/eyvan/sdk/client/identity.py +133 -0
- eyvan-0.0.1/eyvan/sdk/client/jobs.py +518 -0
- eyvan-0.0.1/eyvan/sdk/client/requests.py +165 -0
- eyvan-0.0.1/eyvan/sdk/client/retry.py +62 -0
- eyvan-0.0.1/eyvan/sdk/client/sync.py +538 -0
- eyvan-0.0.1/eyvan/sdk/client/transport.py +550 -0
- eyvan-0.0.1/eyvan/sdk/client/types.py +14 -0
- eyvan-0.0.1/eyvan/sdk/commands/__init__.py +6 -0
- eyvan-0.0.1/eyvan/sdk/commands/artifacts.py +267 -0
- eyvan-0.0.1/eyvan/sdk/commands/assistant.py +597 -0
- eyvan-0.0.1/eyvan/sdk/commands/assistant_claude_code.py +84 -0
- eyvan-0.0.1/eyvan/sdk/commands/autoscale.py +663 -0
- eyvan-0.0.1/eyvan/sdk/commands/capacity.py +901 -0
- eyvan-0.0.1/eyvan/sdk/commands/common.py +103 -0
- eyvan-0.0.1/eyvan/sdk/commands/connect.py +385 -0
- eyvan-0.0.1/eyvan/sdk/commands/contexts.py +94 -0
- eyvan-0.0.1/eyvan/sdk/commands/dashboard.py +199 -0
- eyvan-0.0.1/eyvan/sdk/commands/demo.py +208 -0
- eyvan-0.0.1/eyvan/sdk/commands/deployment.py +124 -0
- eyvan-0.0.1/eyvan/sdk/commands/doctor.py +982 -0
- eyvan-0.0.1/eyvan/sdk/commands/doctor_preflights.py +340 -0
- eyvan-0.0.1/eyvan/sdk/commands/federation.py +317 -0
- eyvan-0.0.1/eyvan/sdk/commands/fleet_status.py +387 -0
- eyvan-0.0.1/eyvan/sdk/commands/fleets.py +755 -0
- eyvan-0.0.1/eyvan/sdk/commands/gcp.py +473 -0
- eyvan-0.0.1/eyvan/sdk/commands/gcp_connect.py +1339 -0
- eyvan-0.0.1/eyvan/sdk/commands/gcp_host_access.py +301 -0
- eyvan-0.0.1/eyvan/sdk/commands/governance.py +561 -0
- eyvan-0.0.1/eyvan/sdk/commands/head.py +3088 -0
- eyvan-0.0.1/eyvan/sdk/commands/head_discovery.py +232 -0
- eyvan-0.0.1/eyvan/sdk/commands/http.py +262 -0
- eyvan-0.0.1/eyvan/sdk/commands/mcp.py +326 -0
- eyvan-0.0.1/eyvan/sdk/commands/operations.py +227 -0
- eyvan-0.0.1/eyvan/sdk/commands/proof.py +1587 -0
- eyvan-0.0.1/eyvan/sdk/commands/query.py +123 -0
- eyvan-0.0.1/eyvan/sdk/commands/receipts.py +433 -0
- eyvan-0.0.1/eyvan/sdk/commands/research.py +238 -0
- eyvan-0.0.1/eyvan/sdk/commands/resources.py +338 -0
- eyvan-0.0.1/eyvan/sdk/commands/runtime.py +1149 -0
- eyvan-0.0.1/eyvan/sdk/commands/services.py +111 -0
- eyvan-0.0.1/eyvan/sdk/commands/soak.py +2157 -0
- eyvan-0.0.1/eyvan/sdk/commands/soak_monitor.py +594 -0
- eyvan-0.0.1/eyvan/sdk/commands/start.py +427 -0
- eyvan-0.0.1/eyvan/sdk/commands/state.py +363 -0
- eyvan-0.0.1/eyvan/sdk/commands/team.py +626 -0
- eyvan-0.0.1/eyvan/sdk/commands/tenancy.py +281 -0
- eyvan-0.0.1/eyvan/sdk/commands/track.py +565 -0
- eyvan-0.0.1/eyvan/sdk/commands/workloads.py +1914 -0
- eyvan-0.0.1/eyvan/sdk/contexts.py +261 -0
- eyvan-0.0.1/eyvan/sdk/execution.py +834 -0
- eyvan-0.0.1/eyvan/sdk/follow.py +415 -0
- eyvan-0.0.1/eyvan/sdk/job_receipt.py +414 -0
- eyvan-0.0.1/eyvan/sdk/lifecycle.py +113 -0
- eyvan-0.0.1/eyvan/sdk/node.py +279 -0
- eyvan-0.0.1/eyvan/sdk/shapes.py +60 -0
- eyvan-0.0.1/eyvan/sdk/spend.py +75 -0
- eyvan-0.0.1/eyvan/sdk/tables.py +161 -0
- eyvan-0.0.1/eyvan/sdk/team_credentials.py +289 -0
- eyvan-0.0.1/eyvan/sdk/terminal.py +133 -0
- eyvan-0.0.1/eyvan/sdk/timeline.py +184 -0
- eyvan-0.0.1/eyvan/sdk/workload_summary.py +204 -0
- eyvan-0.0.1/eyvan/secrets.py +370 -0
- eyvan-0.0.1/eyvan/server/__init__.py +6 -0
- eyvan-0.0.1/eyvan/server/api/__init__.py +67 -0
- eyvan-0.0.1/eyvan/server/api/app.py +4394 -0
- eyvan-0.0.1/eyvan/server/api/assistant.py +1208 -0
- eyvan-0.0.1/eyvan/server/api/assistant_claude_code.py +1082 -0
- eyvan-0.0.1/eyvan/server/api/assistant_presets.py +595 -0
- eyvan-0.0.1/eyvan/server/api/assistant_stream.py +291 -0
- eyvan-0.0.1/eyvan/server/api/attachments.py +190 -0
- eyvan-0.0.1/eyvan/server/api/auth.py +428 -0
- eyvan-0.0.1/eyvan/server/api/bootstrap_admin.py +136 -0
- eyvan-0.0.1/eyvan/server/api/dashboard_sessions.py +575 -0
- eyvan-0.0.1/eyvan/server/api/mcp_routes.py +985 -0
- eyvan-0.0.1/eyvan/server/api/research_routes.py +191 -0
- eyvan-0.0.1/eyvan/server/api/research_runner.py +253 -0
- eyvan-0.0.1/eyvan/server/api/schemas.py +1156 -0
- eyvan-0.0.1/eyvan/server/api/server_bind.py +87 -0
- eyvan-0.0.1/eyvan/server/api/server_logging.py +140 -0
- eyvan-0.0.1/eyvan/server/api/server_startup.py +303 -0
- eyvan-0.0.1/eyvan/server/api/sse.py +72 -0
- eyvan-0.0.1/eyvan/server/api/team_routes.py +374 -0
- eyvan-0.0.1/eyvan/server/api/tracking_proxy.py +285 -0
- eyvan-0.0.1/eyvan/server/controller/__init__.py +71 -0
- eyvan-0.0.1/eyvan/server/controller/_support.py +418 -0
- eyvan-0.0.1/eyvan/server/controller/capacity_commands.py +380 -0
- eyvan-0.0.1/eyvan/server/controller/expansion.py +208 -0
- eyvan-0.0.1/eyvan/server/controller/fleets.py +1233 -0
- eyvan-0.0.1/eyvan/server/controller/lifecycle.py +327 -0
- eyvan-0.0.1/eyvan/server/controller/log_archival.py +343 -0
- eyvan-0.0.1/eyvan/server/controller/loops.py +448 -0
- eyvan-0.0.1/eyvan/server/controller/observation.py +3247 -0
- eyvan-0.0.1/eyvan/server/controller/outbox.py +720 -0
- eyvan-0.0.1/eyvan/server/controller/preemption.py +837 -0
- eyvan-0.0.1/eyvan/server/controller/reclaim.py +462 -0
- eyvan-0.0.1/eyvan/server/controller/scheduling.py +478 -0
- eyvan-0.0.1/eyvan/server/controller/services.py +661 -0
- eyvan-0.0.1/eyvan/server/controller/settlement.py +1519 -0
- eyvan-0.0.1/eyvan/server/controller/staging.py +935 -0
- eyvan-0.0.1/eyvan/server/controller/webhook_delivery.py +264 -0
- eyvan-0.0.1/eyvan/server/controller/workload_commands.py +1936 -0
- eyvan-0.0.1/eyvan/server/introspection.py +139 -0
- eyvan-0.0.1/eyvan/server/invariants.py +612 -0
- eyvan-0.0.1/eyvan/server/local/__init__.py +6 -0
- eyvan-0.0.1/eyvan/server/local/attach_job.py +309 -0
- eyvan-0.0.1/eyvan/server/local/auth.py +286 -0
- eyvan-0.0.1/eyvan/server/local/daemon.py +1385 -0
- eyvan-0.0.1/eyvan/server/local/profile.py +132 -0
- eyvan-0.0.1/eyvan/server/local/tracker.py +345 -0
- eyvan-0.0.1/eyvan/server/persistence/__init__.py +47 -0
- eyvan-0.0.1/eyvan/server/persistence/base.py +635 -0
- eyvan-0.0.1/eyvan/server/persistence/leader.py +125 -0
- eyvan-0.0.1/eyvan/server/persistence/local.py +1587 -0
- eyvan-0.0.1/eyvan/server/persistence/memory.py +23 -0
- eyvan-0.0.1/eyvan/server/persistence/migrate.py +398 -0
- eyvan-0.0.1/eyvan/server/persistence/migrations/__init__.py +6 -0
- eyvan-0.0.1/eyvan/server/persistence/migrations/env.py +65 -0
- eyvan-0.0.1/eyvan/server/persistence/migrations/versions/0002_transactional_outbox.py +84 -0
- eyvan-0.0.1/eyvan/server/persistence/migrations/versions/0003_capacity_pools.py +32 -0
- eyvan-0.0.1/eyvan/server/persistence/migrations/versions/0004_query_indexes.py +52 -0
- eyvan-0.0.1/eyvan/server/persistence/migrations/versions/0005_retention_columns.py +53 -0
- eyvan-0.0.1/eyvan/server/persistence/migrations/versions/0006_artifact_index.py +96 -0
- eyvan-0.0.1/eyvan/server/persistence/migrations/versions/0007_federation_identity.py +81 -0
- eyvan-0.0.1/eyvan/server/persistence/migrations/versions/0008_progress_reports.py +47 -0
- eyvan-0.0.1/eyvan/server/persistence/migrations/versions/0009_tenant_registry.py +64 -0
- eyvan-0.0.1/eyvan/server/persistence/migrations/versions/0010_role_grants.py +58 -0
- eyvan-0.0.1/eyvan/server/persistence/migrations/versions/0011_quota_grants.py +69 -0
- eyvan-0.0.1/eyvan/server/persistence/migrations/versions/0012_audit_event_time.py +49 -0
- eyvan-0.0.1/eyvan/server/persistence/migrations/versions/0012_scoped_artifact_identity.py +290 -0
- eyvan-0.0.1/eyvan/server/persistence/migrations/versions/0013_merge_artifact_audit.py +25 -0
- eyvan-0.0.1/eyvan/server/persistence/migrations/versions/0014_artifact_lifecycle.py +151 -0
- eyvan-0.0.1/eyvan/server/persistence/migrations/versions/0015_attempt_topology.py +66 -0
- eyvan-0.0.1/eyvan/server/persistence/migrations/versions/0016_cell_stages.py +73 -0
- eyvan-0.0.1/eyvan/server/persistence/migrations/versions/0016_credential_rotation.py +70 -0
- eyvan-0.0.1/eyvan/server/persistence/migrations/versions/0016_expansion_admissions.py +74 -0
- eyvan-0.0.1/eyvan/server/persistence/migrations/versions/0017_merge_stage_rot.py +32 -0
- eyvan-0.0.1/eyvan/server/persistence/migrations/versions/0018_service_operations.py +69 -0
- eyvan-0.0.1/eyvan/server/persistence/migrations/versions/0019_webhooks.py +54 -0
- eyvan-0.0.1/eyvan/server/persistence/migrations/versions/0020_team_accounts.py +64 -0
- eyvan-0.0.1/eyvan/server/persistence/migrations/versions/0021_team_requests.py +41 -0
- eyvan-0.0.1/eyvan/server/persistence/migrations/versions/0022_assistant_providers.py +36 -0
- eyvan-0.0.1/eyvan/server/persistence/migrations/versions/0023_assistant_conversations.py +38 -0
- eyvan-0.0.1/eyvan/server/persistence/migrations/versions/0024_research_plans.py +41 -0
- eyvan-0.0.1/eyvan/server/persistence/sqlalchemy.py +2427 -0
- eyvan-0.0.1/eyvan/server/persistence/state.py +1217 -0
- eyvan-0.0.1/eyvan/server/service/__init__.py +101 -0
- eyvan-0.0.1/eyvan/server/service/_control_plane/__init__.py +6 -0
- eyvan-0.0.1/eyvan/server/service/_control_plane/accounts.py +419 -0
- eyvan-0.0.1/eyvan/server/service/_control_plane/artifact_admission.py +263 -0
- eyvan-0.0.1/eyvan/server/service/_control_plane/artifact_collection.py +438 -0
- eyvan-0.0.1/eyvan/server/service/_control_plane/artifact_inventory.py +418 -0
- eyvan-0.0.1/eyvan/server/service/_control_plane/artifact_io.py +257 -0
- eyvan-0.0.1/eyvan/server/service/_control_plane/artifact_recovery.py +300 -0
- eyvan-0.0.1/eyvan/server/service/_control_plane/assistant_conversations.py +185 -0
- eyvan-0.0.1/eyvan/server/service/_control_plane/assistant_providers.py +259 -0
- eyvan-0.0.1/eyvan/server/service/_control_plane/audit.py +487 -0
- eyvan-0.0.1/eyvan/server/service/_control_plane/callable_submission.py +648 -0
- eyvan-0.0.1/eyvan/server/service/_control_plane/cells.py +455 -0
- eyvan-0.0.1/eyvan/server/service/_control_plane/child_submission.py +216 -0
- eyvan-0.0.1/eyvan/server/service/_control_plane/estimates.py +291 -0
- eyvan-0.0.1/eyvan/server/service/_control_plane/events.py +86 -0
- eyvan-0.0.1/eyvan/server/service/_control_plane/expansion.py +796 -0
- eyvan-0.0.1/eyvan/server/service/_control_plane/federation.py +597 -0
- eyvan-0.0.1/eyvan/server/service/_control_plane/fleets.py +795 -0
- eyvan-0.0.1/eyvan/server/service/_control_plane/governance.py +333 -0
- eyvan-0.0.1/eyvan/server/service/_control_plane/lease_settlement.py +510 -0
- eyvan-0.0.1/eyvan/server/service/_control_plane/leases.py +510 -0
- eyvan-0.0.1/eyvan/server/service/_control_plane/policies.py +358 -0
- eyvan-0.0.1/eyvan/server/service/_control_plane/reporting.py +389 -0
- eyvan-0.0.1/eyvan/server/service/_control_plane/research.py +1004 -0
- eyvan-0.0.1/eyvan/server/service/_control_plane/scheduling.py +287 -0
- eyvan-0.0.1/eyvan/server/service/_control_plane/services.py +430 -0
- eyvan-0.0.1/eyvan/server/service/_control_plane/shared.py +879 -0
- eyvan-0.0.1/eyvan/server/service/_control_plane/submission.py +300 -0
- eyvan-0.0.1/eyvan/server/service/_control_plane/team_requests.py +142 -0
- eyvan-0.0.1/eyvan/server/service/_control_plane/tenancy.py +394 -0
- eyvan-0.0.1/eyvan/server/service/_control_plane/transactions.py +154 -0
- eyvan-0.0.1/eyvan/server/service/_control_plane/webhooks.py +202 -0
- eyvan-0.0.1/eyvan/server/service/_control_plane/workload_lifecycle.py +626 -0
- eyvan-0.0.1/eyvan/server/service/_control_plane/workload_settlement.py +492 -0
- eyvan-0.0.1/eyvan/server/service/_control_plane/workload_storage.py +263 -0
- eyvan-0.0.1/eyvan/server/service/authz.py +101 -0
- eyvan-0.0.1/eyvan/server/service/batch.py +136 -0
- eyvan-0.0.1/eyvan/server/service/callable_trust.py +70 -0
- eyvan-0.0.1/eyvan/server/service/control_plane.py +840 -0
- eyvan-0.0.1/eyvan/server/service/credential_rotation.py +302 -0
- eyvan-0.0.1/eyvan/server/service/dag.py +143 -0
- eyvan-0.0.1/eyvan/server/service/errors.py +181 -0
- eyvan-0.0.1/eyvan/server/service/expansion.py +312 -0
- eyvan-0.0.1/eyvan/server/service/federation.py +381 -0
- eyvan-0.0.1/eyvan/server/service/groups.py +116 -0
- eyvan-0.0.1/eyvan/server/service/locality.py +162 -0
- eyvan-0.0.1/eyvan/server/service/pricing_resolver.py +194 -0
- eyvan-0.0.1/eyvan/server/service/provider_diagnostics.py +87 -0
- eyvan-0.0.1/eyvan/server/service/research_losses.py +105 -0
- eyvan-0.0.1/eyvan/server/service/scheduling.py +749 -0
- eyvan-0.0.1/eyvan/server/service/services.py +911 -0
- eyvan-0.0.1/eyvan/server/service/stage.py +505 -0
- eyvan-0.0.1/eyvan/server/service/state.py +68 -0
- eyvan-0.0.1/eyvan/server/service/subjobs.py +175 -0
- eyvan-0.0.1/eyvan/server/service/webhooks.py +176 -0
- eyvan-0.0.1/eyvan/server/service/workload_progress.py +489 -0
- eyvan-0.0.1/eyvan/soak_contract.py +410 -0
- eyvan-0.0.1/eyvan/soak_evidence.py +386 -0
- eyvan-0.0.1/eyvan/track/__init__.py +41 -0
- eyvan-0.0.1/eyvan/track/_format.py +328 -0
- eyvan-0.0.1/eyvan/track/_gcs.py +212 -0
- eyvan-0.0.1/eyvan/track/_rich.py +435 -0
- eyvan-0.0.1/eyvan/track/_run.py +1625 -0
- eyvan-0.0.1/eyvan/track/_store.py +274 -0
- eyvan-0.0.1/eyvan/track/tracker/__init__.py +11 -0
- eyvan-0.0.1/eyvan/track/tracker/__main__.py +11 -0
- eyvan-0.0.1/eyvan/track/tracker/aggregates.py +297 -0
- eyvan-0.0.1/eyvan/track/tracker/app.py +244 -0
- eyvan-0.0.1/eyvan/track/tracker/cli.py +51 -0
- eyvan-0.0.1/eyvan/track/tracker/index.py +682 -0
- eyvan-0.0.1/eyvan/track/tracker/phase2.py +210 -0
- eyvan-0.0.1/eyvan/track/tracker/phase3.py +538 -0
- eyvan-0.0.1/eyvan/track/tracker/phase3_api.py +155 -0
- eyvan-0.0.1/eyvan/track/tracker/phase3_index.py +200 -0
- eyvan-0.0.1/eyvan/track/tracker/phase3_records.py +194 -0
- eyvan-0.0.1/eyvan/track/tracker/records.py +171 -0
- eyvan-0.0.1/eyvan/track/tracker/replay.py +38 -0
- eyvan-0.0.1/eyvan/track/tracker/rich_sql.py +165 -0
- eyvan-0.0.1/eyvan/worker/__init__.py +6 -0
- eyvan-0.0.1/eyvan/worker/agent/__init__.py +30 -0
- eyvan-0.0.1/eyvan/worker/agent/app.py +379 -0
- eyvan-0.0.1/eyvan/worker/agent/cli.py +100 -0
- eyvan-0.0.1/eyvan/worker/agent/client.py +549 -0
- eyvan-0.0.1/eyvan/worker/agent/models.py +378 -0
- eyvan-0.0.1/eyvan/worker/agent/service.py +1215 -0
- eyvan-0.0.1/eyvan/worker/distributed_environment.py +651 -0
- eyvan-0.0.1/eyvan/worker/identity.py +100 -0
- eyvan-0.0.1/eyvan/worker/runtime/__init__.py +123 -0
- eyvan-0.0.1/eyvan/worker/runtime/_multihost_site.py +531 -0
- eyvan-0.0.1/eyvan/worker/runtime/callable_protocol.py +659 -0
- eyvan-0.0.1/eyvan/worker/runtime/callable_worker.py +129 -0
- eyvan-0.0.1/eyvan/worker/runtime/callables.py +12 -0
- eyvan-0.0.1/eyvan/worker/runtime/container.py +781 -0
- eyvan-0.0.1/eyvan/worker/runtime/dependency_entry.py +294 -0
- eyvan-0.0.1/eyvan/worker/runtime/host_accelerators.py +83 -0
- eyvan-0.0.1/eyvan/worker/runtime/http_retry.py +48 -0
- eyvan-0.0.1/eyvan/worker/runtime/in_job.py +206 -0
- eyvan-0.0.1/eyvan/worker/runtime/local_process.py +1044 -0
- eyvan-0.0.1/eyvan/worker/runtime/local_worker.py +243 -0
- eyvan-0.0.1/eyvan/worker/runtime/log_records.py +1472 -0
- eyvan-0.0.1/eyvan/worker/runtime/native_bootstrap.py +749 -0
- eyvan-0.0.1/eyvan/worker/runtime/native_gang.py +983 -0
- eyvan-0.0.1/eyvan/worker/runtime/native_remote.py +479 -0
- eyvan-0.0.1/eyvan/worker/runtime/native_slice.py +1484 -0
- eyvan-0.0.1/eyvan/worker/runtime/native_tls_bootstrap.py +119 -0
- eyvan-0.0.1/eyvan/worker/runtime/native_worker.py +689 -0
- eyvan-0.0.1/eyvan/worker/runtime/node_health.py +491 -0
- eyvan-0.0.1/eyvan/worker/runtime/oci_callable_runner.py +103 -0
- eyvan-0.0.1/eyvan/worker/runtime/oci_callable_stager.py +127 -0
- eyvan-0.0.1/eyvan/worker/runtime/progress.py +190 -0
- eyvan-0.0.1/eyvan/worker/runtime/registry.py +729 -0
- eyvan-0.0.1/eyvan/worker/runtime/results.py +12 -0
- eyvan-0.0.1/eyvan/worker/runtime/secret_materialization.py +219 -0
- eyvan-0.0.1/eyvan/worker/runtime/stage_executor.py +790 -0
- eyvan-0.0.1/eyvan/worker/runtime/systemd_transient.py +2482 -0
- eyvan-0.0.1/eyvan/worker/runtime/workspace_entry.py +166 -0
- eyvan-0.0.1/pyproject.toml +177 -0
eyvan-0.0.1/PKG-INFO
ADDED
|
@@ -0,0 +1,305 @@
|
|
|
1
|
+
Metadata-Version: 2.3
|
|
2
|
+
Name: eyvan
|
|
3
|
+
Version: 0.0.1
|
|
4
|
+
Summary: A policy-aware global fleet control plane with native GCP CPU, GPU, and TPU capacity
|
|
5
|
+
Author: Erfan Zare Chavoshi
|
|
6
|
+
Author-email: Erfan Zare Chavoshi <Erfanzare810@gmail.com>
|
|
7
|
+
License: AGPL-3.0-or-later
|
|
8
|
+
Requires-Dist: alembic>=1.14.0
|
|
9
|
+
Requires-Dist: asyncpg>=0.30.0
|
|
10
|
+
Requires-Dist: click>=8.4.2
|
|
11
|
+
Requires-Dist: cloudpickle>=3.1.0
|
|
12
|
+
Requires-Dist: cryptography>=50.0.0
|
|
13
|
+
Requires-Dist: fastapi>=0.141.1
|
|
14
|
+
Requires-Dist: httpx>=0.27.0
|
|
15
|
+
Requires-Dist: idna>=3.18
|
|
16
|
+
Requires-Dist: opentelemetry-api>=1.28.0
|
|
17
|
+
Requires-Dist: prometheus-client>=0.21.0
|
|
18
|
+
Requires-Dist: pydantic>=2.11.0
|
|
19
|
+
Requires-Dist: pygments>=2.20.0
|
|
20
|
+
Requires-Dist: pyjwt[crypto]>=2.9.0
|
|
21
|
+
Requires-Dist: pyyaml>=6.0
|
|
22
|
+
Requires-Dist: rich>=13.9
|
|
23
|
+
Requires-Dist: sqlalchemy[asyncio]>=2.0.36
|
|
24
|
+
Requires-Dist: starlette>=1.5.0
|
|
25
|
+
Requires-Dist: typing-extensions>=4.12.0
|
|
26
|
+
Requires-Dist: uvicorn[standard]>=0.48.0
|
|
27
|
+
Requires-Dist: pytest>=8.3.0 ; extra == 'dev'
|
|
28
|
+
Requires-Dist: pytest-asyncio>=0.24.0 ; extra == 'dev'
|
|
29
|
+
Requires-Dist: aiosqlite>=0.20.0 ; extra == 'dev'
|
|
30
|
+
Requires-Dist: hypothesis>=6.100.0 ; extra == 'dev'
|
|
31
|
+
Requires-Dist: pytest-cov>=6.0.0 ; extra == 'dev'
|
|
32
|
+
Requires-Dist: detect-secrets>=1.5.0 ; extra == 'dev'
|
|
33
|
+
Requires-Dist: mypy>=1.15 ; extra == 'dev'
|
|
34
|
+
Requires-Dist: pytest-xdist>=3.6 ; extra == 'dev'
|
|
35
|
+
Requires-Dist: ruff==0.15.16 ; extra == 'dev'
|
|
36
|
+
Requires-Dist: import-linter>=2.1 ; extra == 'dev'
|
|
37
|
+
Requires-Dist: pip-audit==2.10.1 ; extra == 'dev'
|
|
38
|
+
Requires-Dist: opentelemetry-sdk==1.45.1 ; extra == 'dev'
|
|
39
|
+
Requires-Dist: google-cloud-storage>=2.18.0 ; extra == 'oci'
|
|
40
|
+
Requires-Python: >=3.11, <3.14
|
|
41
|
+
Provides-Extra: dev
|
|
42
|
+
Provides-Extra: oci
|
|
43
|
+
Description-Content-Type: text/markdown
|
|
44
|
+
|
|
45
|
+
# Eyvan (ایوان)
|
|
46
|
+
|
|
47
|
+
Eyvan is a capacity plane for research compute. You state the shape of work you
|
|
48
|
+
need — `2 × v5p-16, spot, this fleet` — as a digest-verified unsigned Python
|
|
49
|
+
callable submitted to an explicitly trusted project. The plane acquires the
|
|
50
|
+
machines, boots them, dispatches your callable, and returns its result.
|
|
51
|
+
Capacity records show what was requested, what a provider accepted or refused,
|
|
52
|
+
and how long the handover took.
|
|
53
|
+
|
|
54
|
+
## The sixty-second version
|
|
55
|
+
|
|
56
|
+
```bash
|
|
57
|
+
uv sync --extra dev # workspace install + development dependencies
|
|
58
|
+
uv run eyvan up examples/laptop.yaml # start the local loopback CPU fleet before SDK init
|
|
59
|
+
uv run eyvan start # find or point at a control plane
|
|
60
|
+
uv run eyvan doctor # what is missing, named together
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
Eyvan supports Python `>=3.11,<3.14` (the range declared in `pyproject.toml`).
|
|
64
|
+
|
|
65
|
+
```python
|
|
66
|
+
from eyvan import CpuConfig, execute, init
|
|
67
|
+
|
|
68
|
+
init(fleet="laptop")
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
@execute(CpuConfig())
|
|
72
|
+
def train():
|
|
73
|
+
return sum(range(10))
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
Calling `train()` submits the callable and waits, narrating progress:
|
|
77
|
+
`queued`, `provisioning`, `blocked … the plane is retrying (attempt N)`,
|
|
78
|
+
`dispatching`, then your result. The job is durable — it keeps running if your
|
|
79
|
+
client exits (`eyvan workload status <id>` to follow).
|
|
80
|
+
|
|
81
|
+
### With a TPU fleet
|
|
82
|
+
|
|
83
|
+
First configure a fleet with matching TPU pools and a runtime that provides
|
|
84
|
+
JAX. The laptop fleet above has only CPU capacity.
|
|
85
|
+
|
|
86
|
+
```python
|
|
87
|
+
from eyvan import TpuConfig, execute, init
|
|
88
|
+
from eyvan.records import CapacityClass
|
|
89
|
+
|
|
90
|
+
init(fleet="research-us-central1-a")
|
|
91
|
+
|
|
92
|
+
|
|
93
|
+
@execute(TpuConfig(type="v5p-16", pods=2, capacity_class=CapacityClass.SPOT))
|
|
94
|
+
def device_count():
|
|
95
|
+
import jax
|
|
96
|
+
|
|
97
|
+
return jax.device_count()
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
## The SDK in one page
|
|
101
|
+
|
|
102
|
+
### Connecting: `init`
|
|
103
|
+
|
|
104
|
+
```python
|
|
105
|
+
init(address=None, /, *, fleet=None, org_id=None, project_id=None,
|
|
106
|
+
artifact_uri=None, artifact_store=None, ...)
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
With no arguments the SDK discovers the plane the CLI uses (`eyvan start`
|
|
110
|
+
shows you what exists: a local plane, or heads in your project). Point it at
|
|
111
|
+
an explicit plane by address — `eyvan.init("http://10.0.0.5:8080")` — or
|
|
112
|
+
bind a default fleet with `eyvan.init(fleet="research-us-central1-a")`.
|
|
113
|
+
Everything else is scope (`org_id`, `project_id`), where artifacts go (a
|
|
114
|
+
`gs://` root or your own `ArtifactStore` implementation), and fleet-state
|
|
115
|
+
location (`EYVAN_FLEET_STATE_URI`) when agents own distinct capacity
|
|
116
|
+
boundaries.
|
|
117
|
+
|
|
118
|
+
### The shape: `TpuConfig`, `GpuConfig`, `CpuConfig`
|
|
119
|
+
|
|
120
|
+
One decorator takes all three; everything under it is shape-agnostic. The
|
|
121
|
+
TPU config's full surface (`eyvan/sdk/client/jobs.py`):
|
|
122
|
+
|
|
123
|
+
| field | default | meaning |
|
|
124
|
+
|---|---|---|
|
|
125
|
+
| `type` | — | accelerator type, e.g. `"v5p-16"`, `"v6e-8"` |
|
|
126
|
+
| `pods` | `1` | workers — how many slices of `type` the job asks for |
|
|
127
|
+
| `atomic` | `False` | `False` (**elastic**, node-pool style): pack warm cells of the same type and provision only the deficit — going `pods` 2→4 keeps the two warm slices and asks for two more, one lease group, one hardware world per cell. `True`: one exact-shape provider resource, one hardware world spanning every pod — what single-mesh training needs |
|
|
128
|
+
| `capacity_class` | Spot preference | `SPOT`, `ON_DEMAND`, `RESERVED`, or `FLEX_START`; an explicit value is exact. If omitted, a reserved-only fleet may substitute `RESERVED` |
|
|
129
|
+
| `max_retries` | `DEFAULT` | retries for **lost capacity** attempts |
|
|
130
|
+
| `max_preemption_retries` | `10` | restarts after the provider reclaims spot — deliberately generous; reclamation is the cheap failure |
|
|
131
|
+
| `max_failure_retries` | `0` | retries of the job's *own* failure — deliberately stingy; a non-zero exit usually repeats, and re-running it costs an accelerator |
|
|
132
|
+
| `secret_mounts` | `{}` | secret **references** resolved at dispatch into env vars on the cell — a reference is what gets persisted, never the value |
|
|
133
|
+
| `checkpointable` / `checkpoint_hook` / `checkpoint_output_uri` | `False`/— | the scheduler grants preemption-checkpoint time only when a real hook is named; otherwise a reclaimed job restarts from zero |
|
|
134
|
+
| `can_submit_children` | `False` | lets the job submit children under your identity — off by default; a credential nobody asked for is one nobody is watching |
|
|
135
|
+
| `dependencies` | `()` | packages installed on the cell before your callable loads — adding a library should not mean rebuilding an image |
|
|
136
|
+
|
|
137
|
+
### The decorator: `execute`
|
|
138
|
+
|
|
139
|
+
```python
|
|
140
|
+
@execute(TpuConfig(type="v6e-8", pods=4), workspace="src/")
|
|
141
|
+
def run(epochs: int):
|
|
142
|
+
...
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
`workspace=` accepts a directory path and ships that tree to the worker's
|
|
146
|
+
working directory before the callable imports. Omit it to derive the workspace
|
|
147
|
+
from the decorated function's source-file directory; interactive callables
|
|
148
|
+
without a source file need an explicit path. Set `workspace=False` to disable
|
|
149
|
+
workspace shipping.
|
|
150
|
+
|
|
151
|
+
### Calling: blocking wait, or detached handle
|
|
152
|
+
|
|
153
|
+
```python
|
|
154
|
+
result = run(epochs=3) # blocks; live progress lines; returns your value
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
```python
|
|
158
|
+
job = run.submit(epochs=3) # EyvanJob — detach, follow, intervene
|
|
159
|
+
job.status() # WorkloadState
|
|
160
|
+
job.logs() # the flattened, globally-ranked log stream
|
|
161
|
+
job.wait(timeout=600, progress=True) # blocking wait, same narration
|
|
162
|
+
job.result(timeout=3600) # your value, or EyvanJobError with the reason
|
|
163
|
+
job.cancel() # durable cancel
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
Your callable's *return value* comes back through the artifact store; its
|
|
167
|
+
imports resolve on the cell (image packages + `dependencies` + whatever
|
|
168
|
+
`workspace` shipped). Identical callables deduplicate by content digest;
|
|
169
|
+
a concurrent upload verifies the existing object's digest before using it.
|
|
170
|
+
See [artifact-safety](docs/artifact-safety.md).
|
|
171
|
+
|
|
172
|
+
One more client-side knob worth knowing: the returned job exposes its
|
|
173
|
+
transport (`.base_url`) so tooling built on the SDK can follow the same
|
|
174
|
+
plane the SDK followed, without re-deriving discovery.
|
|
175
|
+
|
|
176
|
+
Failure narration is part of the API contract: a refused capacity attempt
|
|
177
|
+
renders as `blocked | … | the plane is retrying (attempt N)` with the
|
|
178
|
+
provider's diagnostic, and a terminal failure arrives as an exception whose
|
|
179
|
+
message contains the provider's own sentence — not a bare exit code.
|
|
180
|
+
|
|
181
|
+
## Developing on top of Eyvan
|
|
182
|
+
|
|
183
|
+
Four seams, in order of how often you need them:
|
|
184
|
+
|
|
185
|
+
1. **A different shape** — no code: a `TpuConfig`/`GpuConfig`/`CpuConfig`
|
|
186
|
+
value. Check the shape is real for you first:
|
|
187
|
+
`eyvan capacity quota --fits v5p-16:2` (quota **and** admission
|
|
188
|
+
permission **and** supply are three different gates).
|
|
189
|
+
2. **A different fleet** — a YAML config: `eyvan up <config>` from a
|
|
190
|
+
hand-written file (see `examples/fleet.yaml`, `examples/laptop.yaml`) or
|
|
191
|
+
a generated fleet (`eyvan up --region <region> --preemptible`, or
|
|
192
|
+
`eyvan up --quota-based --zone <zone> --preemptible`). Node types, runtime
|
|
193
|
+
env, and autoscaling knobs live in the config, not in your callable.
|
|
194
|
+
3. **A different cloud** — a provider package with a driver and transport.
|
|
195
|
+
External plugins default to single-machine cells; multi-worker planning
|
|
196
|
+
also needs an in-tree capability entry and a supporting pool factory.
|
|
197
|
+
See [providers](docs/providers.md) for the ABI and conformance contract.
|
|
198
|
+
4. **A different workflow** — composition: `can_submit_children=True` grants
|
|
199
|
+
your job a submission capability under your identity (fan-out workers,
|
|
200
|
+
coordinator patterns), and checkpointing hooks let long spot jobs survive
|
|
201
|
+
reclamation by design rather than by luck.
|
|
202
|
+
|
|
203
|
+
### Developing Eyvan itself
|
|
204
|
+
|
|
205
|
+
```bash
|
|
206
|
+
git clone <this repo> && cd eyvan
|
|
207
|
+
uv sync --extra dev # editable install + dev deps (pytest, pytest-asyncio)
|
|
208
|
+
npm --prefix dashboard ci
|
|
209
|
+
npm --prefix dashboard run build # build the SPA before Python tests
|
|
210
|
+
uv run pytest tests -m fast -q # smoke subset for iteration, not a release gate
|
|
211
|
+
uv run pytest tests -q -rs # full suite; real PostgreSQL requires the test fixture setup
|
|
212
|
+
uv run ruff check eyvan tests # lint (line 121, py3.11)
|
|
213
|
+
uv run eyvan-server --log-level info # run the plane from source
|
|
214
|
+
uv run eyvan-agent --host 127.0.0.1 --port 8090 --allow-unauthenticated # local dev only
|
|
215
|
+
```
|
|
216
|
+
|
|
217
|
+
Verify the dashboard from a fresh checkout with the commands in
|
|
218
|
+
[Contributing — Dashboard](CONTRIBUTING.md#running-the-tests):
|
|
219
|
+
|
|
220
|
+
```bash
|
|
221
|
+
npm --prefix dashboard ci
|
|
222
|
+
npm --prefix dashboard test
|
|
223
|
+
npm --prefix dashboard run build
|
|
224
|
+
```
|
|
225
|
+
|
|
226
|
+
The rules that keep the package honest — enforce them in review, not in
|
|
227
|
+
memory:
|
|
228
|
+
|
|
229
|
+
- **Provider boundary:** nothing that decides (scheduler, planner, durable
|
|
230
|
+
model) may name a provider; `tests/test_provider_boundary.py` enforces it.
|
|
231
|
+
- **Claims need receipts:** a behavior claim cites a recorded run; hardware
|
|
232
|
+
claims go through `eyvan proof` (exit 0 pass, 1 fail, 2 *did not exercise
|
|
233
|
+
the behaviour*, 3 refusal) — see [proofs](docs/proofs.md).
|
|
234
|
+
- **Tests assert public behavior:** state transitions, API outputs, parity —
|
|
235
|
+
not private helper calls or log strings.
|
|
236
|
+
- **Diagnostics travel with failures:** a CLI or provider failure raises with
|
|
237
|
+
its own words attached (`GcsCommandError` carries command + stderr).
|
|
238
|
+
- Architecture decisions are design records under
|
|
239
|
+
[docs/design/](docs/design/0001-scoped-artifact-lifecycle.md), each stating
|
|
240
|
+
its real implementation status.
|
|
241
|
+
|
|
242
|
+
## The ideas everything else follows from
|
|
243
|
+
|
|
244
|
+
1. **You state the shape, not the pool.** The scheduler and capacity planner
|
|
245
|
+
decide where that shape can exist.
|
|
246
|
+
2. **Receipts or it did not happen.** Capacity claims cite recorded runs.
|
|
247
|
+
3. **Failure narrates itself.** Diagnostics render, never `FAILED`.
|
|
248
|
+
4. **Nothing that decides names a provider.** Clouds plug in; the core stays
|
|
249
|
+
agnostic.
|
|
250
|
+
5. **Durable state survives the plane.** A restarted `eyvan-server`
|
|
251
|
+
reconciles the whole world from its durable store.
|
|
252
|
+
|
|
253
|
+
## Concepts
|
|
254
|
+
|
|
255
|
+
| term | meaning |
|
|
256
|
+
|---------|--------------------------------------------------------------------|
|
|
257
|
+
| plane | the control plane (`eyvan-server`) — scheduler, planner, state |
|
|
258
|
+
| agent | a cell agent (`eyvan-agent`) owning machines on one backend |
|
|
259
|
+
| fleet | a named set of capacity pools you can submit into |
|
|
260
|
+
| pool | one (backend, accelerator, capacity class, zone) combination |
|
|
261
|
+
| cell | one acquired allocation (e.g. one spot queued resource) |
|
|
262
|
+
| workload| your callable + its requested shape, moving through durable states |
|
|
263
|
+
|
|
264
|
+
## Where it runs
|
|
265
|
+
|
|
266
|
+
Registered capacity backends: `local` (loopback laptop fleets), `gcp-tpu`
|
|
267
|
+
(generated zone fleets driving TPU queued resources, spot or on-demand),
|
|
268
|
+
`gcp-compute`, the `gcp` umbrella, `aws-ec2` (the worked provider example)
|
|
269
|
+
and the `aws` umbrella, `azure-vm` and the `azure` umbrella, `kubernetes`
|
|
270
|
+
(`k8s`) against a real API server, `manual`, `onprem-ssh`, and `gcp-attach`
|
|
271
|
+
(an existing Cloud TPU VM attached with `eyvan gcp connect`; observed, never
|
|
272
|
+
created or deleted).
|
|
273
|
+
|
|
274
|
+
Backend availability is not proof of qualification on your infrastructure.
|
|
275
|
+
GCP TPU is the backend with live hardware runs; the on-premises SSH driver is
|
|
276
|
+
code with no run against a real SSH host yet. See [proofs](docs/proofs.md) for
|
|
277
|
+
evidence requirements and backend-specific limits.
|
|
278
|
+
|
|
279
|
+
## The docs map
|
|
280
|
+
|
|
281
|
+
New to the project? Start with the [tutorial](docs/tutorial/README.md) —
|
|
282
|
+
seventeen source-grounded parts that walk from "what is Eyvan" through the SDK,
|
|
283
|
+
the control plane, providers, operations, deployment, and an explicit Spot TPU example.
|
|
284
|
+
|
|
285
|
+
| page | what it answers |
|
|
286
|
+
|---|---|
|
|
287
|
+
| [tutorial](docs/tutorial/README.md) | a part-per-subsystem tutorial, grounded in the source |
|
|
288
|
+
| [eyvan-explained](docs/eyvan-explained.md) | the mental model, one workload's full journey |
|
|
289
|
+
| [install](docs/install.md) | laptop path, the fifteen, GCP head, secrets |
|
|
290
|
+
| [operate](docs/operate.md) | the runbook: fleets, workloads, capacity, zone racing |
|
|
291
|
+
| [runtimes](docs/runtimes.md) | the two provisioning models, the defaults profile, custom images |
|
|
292
|
+
| [proofs](docs/proofs.md) | what is proven, with receipts; known rough edges |
|
|
293
|
+
| [providers](docs/providers.md) | writing a capacity provider; the conformance contract |
|
|
294
|
+
| [security](docs/security.md) | trust boundaries, tokens, what jobs can do |
|
|
295
|
+
| [env-surface](docs/env-surface.md) | every `EYVAN_*` variable |
|
|
296
|
+
| [artifact-safety](docs/artifact-safety.md) | tenancy, lifecycle, the digest-addressed store |
|
|
297
|
+
| [troubleshoot](docs/troubleshoot.md) | symptom → cause → action tables |
|
|
298
|
+
| [design records](docs/design/0001-scoped-artifact-lifecycle.md) | the ADRs and their real status |
|
|
299
|
+
|
|
300
|
+
## What is proven
|
|
301
|
+
|
|
302
|
+
See [proofs](docs/proofs.md) for proof criteria and evidence limits. After a
|
|
303
|
+
restart, use the intended durable state and matching credentials; inspect
|
|
304
|
+
quarantined leases before intervening. See [operate](docs/operate.md) and
|
|
305
|
+
[troubleshoot](docs/troubleshoot.md) for recovery procedures.
|
eyvan-0.0.1/README.md
ADDED
|
@@ -0,0 +1,261 @@
|
|
|
1
|
+
# Eyvan (ایوان)
|
|
2
|
+
|
|
3
|
+
Eyvan is a capacity plane for research compute. You state the shape of work you
|
|
4
|
+
need — `2 × v5p-16, spot, this fleet` — as a digest-verified unsigned Python
|
|
5
|
+
callable submitted to an explicitly trusted project. The plane acquires the
|
|
6
|
+
machines, boots them, dispatches your callable, and returns its result.
|
|
7
|
+
Capacity records show what was requested, what a provider accepted or refused,
|
|
8
|
+
and how long the handover took.
|
|
9
|
+
|
|
10
|
+
## The sixty-second version
|
|
11
|
+
|
|
12
|
+
```bash
|
|
13
|
+
uv sync --extra dev # workspace install + development dependencies
|
|
14
|
+
uv run eyvan up examples/laptop.yaml # start the local loopback CPU fleet before SDK init
|
|
15
|
+
uv run eyvan start # find or point at a control plane
|
|
16
|
+
uv run eyvan doctor # what is missing, named together
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
Eyvan supports Python `>=3.11,<3.14` (the range declared in `pyproject.toml`).
|
|
20
|
+
|
|
21
|
+
```python
|
|
22
|
+
from eyvan import CpuConfig, execute, init
|
|
23
|
+
|
|
24
|
+
init(fleet="laptop")
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
@execute(CpuConfig())
|
|
28
|
+
def train():
|
|
29
|
+
return sum(range(10))
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
Calling `train()` submits the callable and waits, narrating progress:
|
|
33
|
+
`queued`, `provisioning`, `blocked … the plane is retrying (attempt N)`,
|
|
34
|
+
`dispatching`, then your result. The job is durable — it keeps running if your
|
|
35
|
+
client exits (`eyvan workload status <id>` to follow).
|
|
36
|
+
|
|
37
|
+
### With a TPU fleet
|
|
38
|
+
|
|
39
|
+
First configure a fleet with matching TPU pools and a runtime that provides
|
|
40
|
+
JAX. The laptop fleet above has only CPU capacity.
|
|
41
|
+
|
|
42
|
+
```python
|
|
43
|
+
from eyvan import TpuConfig, execute, init
|
|
44
|
+
from eyvan.records import CapacityClass
|
|
45
|
+
|
|
46
|
+
init(fleet="research-us-central1-a")
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
@execute(TpuConfig(type="v5p-16", pods=2, capacity_class=CapacityClass.SPOT))
|
|
50
|
+
def device_count():
|
|
51
|
+
import jax
|
|
52
|
+
|
|
53
|
+
return jax.device_count()
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
## The SDK in one page
|
|
57
|
+
|
|
58
|
+
### Connecting: `init`
|
|
59
|
+
|
|
60
|
+
```python
|
|
61
|
+
init(address=None, /, *, fleet=None, org_id=None, project_id=None,
|
|
62
|
+
artifact_uri=None, artifact_store=None, ...)
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
With no arguments the SDK discovers the plane the CLI uses (`eyvan start`
|
|
66
|
+
shows you what exists: a local plane, or heads in your project). Point it at
|
|
67
|
+
an explicit plane by address — `eyvan.init("http://10.0.0.5:8080")` — or
|
|
68
|
+
bind a default fleet with `eyvan.init(fleet="research-us-central1-a")`.
|
|
69
|
+
Everything else is scope (`org_id`, `project_id`), where artifacts go (a
|
|
70
|
+
`gs://` root or your own `ArtifactStore` implementation), and fleet-state
|
|
71
|
+
location (`EYVAN_FLEET_STATE_URI`) when agents own distinct capacity
|
|
72
|
+
boundaries.
|
|
73
|
+
|
|
74
|
+
### The shape: `TpuConfig`, `GpuConfig`, `CpuConfig`
|
|
75
|
+
|
|
76
|
+
One decorator takes all three; everything under it is shape-agnostic. The
|
|
77
|
+
TPU config's full surface (`eyvan/sdk/client/jobs.py`):
|
|
78
|
+
|
|
79
|
+
| field | default | meaning |
|
|
80
|
+
|---|---|---|
|
|
81
|
+
| `type` | — | accelerator type, e.g. `"v5p-16"`, `"v6e-8"` |
|
|
82
|
+
| `pods` | `1` | workers — how many slices of `type` the job asks for |
|
|
83
|
+
| `atomic` | `False` | `False` (**elastic**, node-pool style): pack warm cells of the same type and provision only the deficit — going `pods` 2→4 keeps the two warm slices and asks for two more, one lease group, one hardware world per cell. `True`: one exact-shape provider resource, one hardware world spanning every pod — what single-mesh training needs |
|
|
84
|
+
| `capacity_class` | Spot preference | `SPOT`, `ON_DEMAND`, `RESERVED`, or `FLEX_START`; an explicit value is exact. If omitted, a reserved-only fleet may substitute `RESERVED` |
|
|
85
|
+
| `max_retries` | `DEFAULT` | retries for **lost capacity** attempts |
|
|
86
|
+
| `max_preemption_retries` | `10` | restarts after the provider reclaims spot — deliberately generous; reclamation is the cheap failure |
|
|
87
|
+
| `max_failure_retries` | `0` | retries of the job's *own* failure — deliberately stingy; a non-zero exit usually repeats, and re-running it costs an accelerator |
|
|
88
|
+
| `secret_mounts` | `{}` | secret **references** resolved at dispatch into env vars on the cell — a reference is what gets persisted, never the value |
|
|
89
|
+
| `checkpointable` / `checkpoint_hook` / `checkpoint_output_uri` | `False`/— | the scheduler grants preemption-checkpoint time only when a real hook is named; otherwise a reclaimed job restarts from zero |
|
|
90
|
+
| `can_submit_children` | `False` | lets the job submit children under your identity — off by default; a credential nobody asked for is one nobody is watching |
|
|
91
|
+
| `dependencies` | `()` | packages installed on the cell before your callable loads — adding a library should not mean rebuilding an image |
|
|
92
|
+
|
|
93
|
+
### The decorator: `execute`
|
|
94
|
+
|
|
95
|
+
```python
|
|
96
|
+
@execute(TpuConfig(type="v6e-8", pods=4), workspace="src/")
|
|
97
|
+
def run(epochs: int):
|
|
98
|
+
...
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
`workspace=` accepts a directory path and ships that tree to the worker's
|
|
102
|
+
working directory before the callable imports. Omit it to derive the workspace
|
|
103
|
+
from the decorated function's source-file directory; interactive callables
|
|
104
|
+
without a source file need an explicit path. Set `workspace=False` to disable
|
|
105
|
+
workspace shipping.
|
|
106
|
+
|
|
107
|
+
### Calling: blocking wait, or detached handle
|
|
108
|
+
|
|
109
|
+
```python
|
|
110
|
+
result = run(epochs=3) # blocks; live progress lines; returns your value
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
```python
|
|
114
|
+
job = run.submit(epochs=3) # EyvanJob — detach, follow, intervene
|
|
115
|
+
job.status() # WorkloadState
|
|
116
|
+
job.logs() # the flattened, globally-ranked log stream
|
|
117
|
+
job.wait(timeout=600, progress=True) # blocking wait, same narration
|
|
118
|
+
job.result(timeout=3600) # your value, or EyvanJobError with the reason
|
|
119
|
+
job.cancel() # durable cancel
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
Your callable's *return value* comes back through the artifact store; its
|
|
123
|
+
imports resolve on the cell (image packages + `dependencies` + whatever
|
|
124
|
+
`workspace` shipped). Identical callables deduplicate by content digest;
|
|
125
|
+
a concurrent upload verifies the existing object's digest before using it.
|
|
126
|
+
See [artifact-safety](docs/artifact-safety.md).
|
|
127
|
+
|
|
128
|
+
One more client-side knob worth knowing: the returned job exposes its
|
|
129
|
+
transport (`.base_url`) so tooling built on the SDK can follow the same
|
|
130
|
+
plane the SDK followed, without re-deriving discovery.
|
|
131
|
+
|
|
132
|
+
Failure narration is part of the API contract: a refused capacity attempt
|
|
133
|
+
renders as `blocked | … | the plane is retrying (attempt N)` with the
|
|
134
|
+
provider's diagnostic, and a terminal failure arrives as an exception whose
|
|
135
|
+
message contains the provider's own sentence — not a bare exit code.
|
|
136
|
+
|
|
137
|
+
## Developing on top of Eyvan
|
|
138
|
+
|
|
139
|
+
Four seams, in order of how often you need them:
|
|
140
|
+
|
|
141
|
+
1. **A different shape** — no code: a `TpuConfig`/`GpuConfig`/`CpuConfig`
|
|
142
|
+
value. Check the shape is real for you first:
|
|
143
|
+
`eyvan capacity quota --fits v5p-16:2` (quota **and** admission
|
|
144
|
+
permission **and** supply are three different gates).
|
|
145
|
+
2. **A different fleet** — a YAML config: `eyvan up <config>` from a
|
|
146
|
+
hand-written file (see `examples/fleet.yaml`, `examples/laptop.yaml`) or
|
|
147
|
+
a generated fleet (`eyvan up --region <region> --preemptible`, or
|
|
148
|
+
`eyvan up --quota-based --zone <zone> --preemptible`). Node types, runtime
|
|
149
|
+
env, and autoscaling knobs live in the config, not in your callable.
|
|
150
|
+
3. **A different cloud** — a provider package with a driver and transport.
|
|
151
|
+
External plugins default to single-machine cells; multi-worker planning
|
|
152
|
+
also needs an in-tree capability entry and a supporting pool factory.
|
|
153
|
+
See [providers](docs/providers.md) for the ABI and conformance contract.
|
|
154
|
+
4. **A different workflow** — composition: `can_submit_children=True` grants
|
|
155
|
+
your job a submission capability under your identity (fan-out workers,
|
|
156
|
+
coordinator patterns), and checkpointing hooks let long spot jobs survive
|
|
157
|
+
reclamation by design rather than by luck.
|
|
158
|
+
|
|
159
|
+
### Developing Eyvan itself
|
|
160
|
+
|
|
161
|
+
```bash
|
|
162
|
+
git clone <this repo> && cd eyvan
|
|
163
|
+
uv sync --extra dev # editable install + dev deps (pytest, pytest-asyncio)
|
|
164
|
+
npm --prefix dashboard ci
|
|
165
|
+
npm --prefix dashboard run build # build the SPA before Python tests
|
|
166
|
+
uv run pytest tests -m fast -q # smoke subset for iteration, not a release gate
|
|
167
|
+
uv run pytest tests -q -rs # full suite; real PostgreSQL requires the test fixture setup
|
|
168
|
+
uv run ruff check eyvan tests # lint (line 121, py3.11)
|
|
169
|
+
uv run eyvan-server --log-level info # run the plane from source
|
|
170
|
+
uv run eyvan-agent --host 127.0.0.1 --port 8090 --allow-unauthenticated # local dev only
|
|
171
|
+
```
|
|
172
|
+
|
|
173
|
+
Verify the dashboard from a fresh checkout with the commands in
|
|
174
|
+
[Contributing — Dashboard](CONTRIBUTING.md#running-the-tests):
|
|
175
|
+
|
|
176
|
+
```bash
|
|
177
|
+
npm --prefix dashboard ci
|
|
178
|
+
npm --prefix dashboard test
|
|
179
|
+
npm --prefix dashboard run build
|
|
180
|
+
```
|
|
181
|
+
|
|
182
|
+
The rules that keep the package honest — enforce them in review, not in
|
|
183
|
+
memory:
|
|
184
|
+
|
|
185
|
+
- **Provider boundary:** nothing that decides (scheduler, planner, durable
|
|
186
|
+
model) may name a provider; `tests/test_provider_boundary.py` enforces it.
|
|
187
|
+
- **Claims need receipts:** a behavior claim cites a recorded run; hardware
|
|
188
|
+
claims go through `eyvan proof` (exit 0 pass, 1 fail, 2 *did not exercise
|
|
189
|
+
the behaviour*, 3 refusal) — see [proofs](docs/proofs.md).
|
|
190
|
+
- **Tests assert public behavior:** state transitions, API outputs, parity —
|
|
191
|
+
not private helper calls or log strings.
|
|
192
|
+
- **Diagnostics travel with failures:** a CLI or provider failure raises with
|
|
193
|
+
its own words attached (`GcsCommandError` carries command + stderr).
|
|
194
|
+
- Architecture decisions are design records under
|
|
195
|
+
[docs/design/](docs/design/0001-scoped-artifact-lifecycle.md), each stating
|
|
196
|
+
its real implementation status.
|
|
197
|
+
|
|
198
|
+
## The ideas everything else follows from
|
|
199
|
+
|
|
200
|
+
1. **You state the shape, not the pool.** The scheduler and capacity planner
|
|
201
|
+
decide where that shape can exist.
|
|
202
|
+
2. **Receipts or it did not happen.** Capacity claims cite recorded runs.
|
|
203
|
+
3. **Failure narrates itself.** Diagnostics render, never `FAILED`.
|
|
204
|
+
4. **Nothing that decides names a provider.** Clouds plug in; the core stays
|
|
205
|
+
agnostic.
|
|
206
|
+
5. **Durable state survives the plane.** A restarted `eyvan-server`
|
|
207
|
+
reconciles the whole world from its durable store.
|
|
208
|
+
|
|
209
|
+
## Concepts
|
|
210
|
+
|
|
211
|
+
| term | meaning |
|
|
212
|
+
|---------|--------------------------------------------------------------------|
|
|
213
|
+
| plane | the control plane (`eyvan-server`) — scheduler, planner, state |
|
|
214
|
+
| agent | a cell agent (`eyvan-agent`) owning machines on one backend |
|
|
215
|
+
| fleet | a named set of capacity pools you can submit into |
|
|
216
|
+
| pool | one (backend, accelerator, capacity class, zone) combination |
|
|
217
|
+
| cell | one acquired allocation (e.g. one spot queued resource) |
|
|
218
|
+
| workload| your callable + its requested shape, moving through durable states |
|
|
219
|
+
|
|
220
|
+
## Where it runs
|
|
221
|
+
|
|
222
|
+
Registered capacity backends: `local` (loopback laptop fleets), `gcp-tpu`
|
|
223
|
+
(generated zone fleets driving TPU queued resources, spot or on-demand),
|
|
224
|
+
`gcp-compute`, the `gcp` umbrella, `aws-ec2` (the worked provider example)
|
|
225
|
+
and the `aws` umbrella, `azure-vm` and the `azure` umbrella, `kubernetes`
|
|
226
|
+
(`k8s`) against a real API server, `manual`, `onprem-ssh`, and `gcp-attach`
|
|
227
|
+
(an existing Cloud TPU VM attached with `eyvan gcp connect`; observed, never
|
|
228
|
+
created or deleted).
|
|
229
|
+
|
|
230
|
+
Backend availability is not proof of qualification on your infrastructure.
|
|
231
|
+
GCP TPU is the backend with live hardware runs; the on-premises SSH driver is
|
|
232
|
+
code with no run against a real SSH host yet. See [proofs](docs/proofs.md) for
|
|
233
|
+
evidence requirements and backend-specific limits.
|
|
234
|
+
|
|
235
|
+
## The docs map
|
|
236
|
+
|
|
237
|
+
New to the project? Start with the [tutorial](docs/tutorial/README.md) —
|
|
238
|
+
seventeen source-grounded parts that walk from "what is Eyvan" through the SDK,
|
|
239
|
+
the control plane, providers, operations, deployment, and an explicit Spot TPU example.
|
|
240
|
+
|
|
241
|
+
| page | what it answers |
|
|
242
|
+
|---|---|
|
|
243
|
+
| [tutorial](docs/tutorial/README.md) | a part-per-subsystem tutorial, grounded in the source |
|
|
244
|
+
| [eyvan-explained](docs/eyvan-explained.md) | the mental model, one workload's full journey |
|
|
245
|
+
| [install](docs/install.md) | laptop path, the fifteen, GCP head, secrets |
|
|
246
|
+
| [operate](docs/operate.md) | the runbook: fleets, workloads, capacity, zone racing |
|
|
247
|
+
| [runtimes](docs/runtimes.md) | the two provisioning models, the defaults profile, custom images |
|
|
248
|
+
| [proofs](docs/proofs.md) | what is proven, with receipts; known rough edges |
|
|
249
|
+
| [providers](docs/providers.md) | writing a capacity provider; the conformance contract |
|
|
250
|
+
| [security](docs/security.md) | trust boundaries, tokens, what jobs can do |
|
|
251
|
+
| [env-surface](docs/env-surface.md) | every `EYVAN_*` variable |
|
|
252
|
+
| [artifact-safety](docs/artifact-safety.md) | tenancy, lifecycle, the digest-addressed store |
|
|
253
|
+
| [troubleshoot](docs/troubleshoot.md) | symptom → cause → action tables |
|
|
254
|
+
| [design records](docs/design/0001-scoped-artifact-lifecycle.md) | the ADRs and their real status |
|
|
255
|
+
|
|
256
|
+
## What is proven
|
|
257
|
+
|
|
258
|
+
See [proofs](docs/proofs.md) for proof criteria and evidence limits. After a
|
|
259
|
+
restart, use the intended durable state and matching credentials; inspect
|
|
260
|
+
quarantined leases before intervening. See [operate](docs/operate.md) and
|
|
261
|
+
[troubleshoot](docs/troubleshoot.md) for recovery procedures.
|