{
  "schema": "aicl-tool/0.1",
  "service": "CTCL",
  "version": "0.1",
  "title": "Common Temporal Coordinate Layer",
  "summary": "Verified reference instant + heterogeneous time transformation for agents. Read this, then call the endpoints. Same instant, different representations.",
  "base_url": "https://commoninstant.org",
  "runtime_enabled": true,
  "sdk": "https://commoninstant.org/sdk.js",
  "core_rule": "Do not ask only 'what time is it'. Ask: which reference instant, under which timescale, from which source, transformed into which local system.",
  "honesty": "Source is a millisecond-grade edge wall clock. ns/us fields are format-padding; check quality.precision + estimated_uncertainty_ns before trusting sub-ms.",
  "tools": [
    {
      "name": "now",
      "method": "GET",
      "path": "/v1/now",
      "desc": "Verified reference instant: encodings, timescales, source, uncertainty, policy, a stable instant_id.",
      "input": {},
      "output": "instant+encodings+timescales+source+quality+policy"
    },
    {
      "name": "attest-now",
      "method": "POST",
      "path": "/v1/attest-now",
      "desc": "Sign a CTCL T2 server-observed instant bound to a caller nonce and opaque context digest; no public KV write or principal authority.",
      "input": {
        "nonce": "32-128 lowercase hex characters, caller-generated",
        "context_digest": "64 lowercase hex characters (SHA-256)"
      },
      "output": "attestation + Ed25519 signature over CTCL-ATTEST-NOW/V1 newline canonical_json(attestation)"
    },
    {
      "name": "timescales",
      "method": "GET",
      "path": "/v1/timescales",
      "desc": "Supported timescales.",
      "input": {},
      "output": "list"
    },
    {
      "name": "encodings",
      "method": "GET",
      "path": "/v1/encodings",
      "desc": "Supported encodings.",
      "input": {},
      "output": "list"
    },
    {
      "name": "convert",
      "method": "POST",
      "path": "/v1/convert",
      "desc": "Convert a time value across encodings/timescales/timezones (precision-preserving).",
      "input": {
        "input": {
          "value": "string",
          "encoding": "unix_s|unix_ms|unix_us|unix_ns|rfc3339",
          "timescale": "utc|posix"
        },
        "output": {
          "encoding": "…",
          "timezone": "IANA (optional)"
        }
      },
      "output": "output.value + canonical_unix_ns + quality.lossless"
    },
    {
      "name": "transform",
      "method": "POST",
      "path": "/v1/transform",
      "desc": "Map a reference (parent) time into a custom linear-rate system (game world / accelerated sim / child clock).",
      "input": {
        "value": "string (parent time)",
        "value_encoding": "unix_s",
        "system": {
          "parent": "ctcl:system:unix",
          "epoch": {
            "parent_value": "unix_s"
          },
          "rate": {
            "value": "number"
          },
          "offset": "number",
          "calendar": {
            "day_seconds": "int",
            "year_days": "int"
          }
        }
      },
      "output": "system time + optional world calendar"
    },
    {
      "name": "register-instant",
      "method": "POST",
      "path": "/v1/instants",
      "desc": "Register a reference instant I* (the current instant, or a given value) → get a shareable id. THE multi-agent primitive: another agent GETs that id and aligns on the exact same instant. Also returns a human `share` URL (/i/{id}, §4.4).",
      "input": {
        "value": "string? (default: now)",
        "encoding": "unix_s|…?",
        "timescale": "utc?",
        "label": "string?",
        "meta": "object?"
      },
      "output": "instant_id + retrieve URL + share URL + all encodings/timescales + optional Ed25519 signature (§31)"
    },
    {
      "name": "get-instant",
      "method": "GET",
      "path": "/v1/instant/{id}",
      "desc": "Retrieve a registered instant by id — aligns you on the same I* another agent registered.",
      "input": {
        "id": "ctcl:instant:… or bare uuid"
      },
      "output": "instant record + all encodings/timescales"
    },
    {
      "name": "create-system",
      "method": "POST",
      "path": "/v1/systems",
      "desc": "Persist a custom linear-rate time system (game world / accelerated sim / child clock) for reuse.",
      "input": {
        "id": "user:game_world",
        "parent": "ctcl:system:unix",
        "epoch": {
          "parent_value": "unix_s"
        },
        "rate": {
          "value": "number"
        },
        "offset": "number?",
        "calendar": {
          "day_seconds": "int",
          "year_days": "int"
        }
      },
      "output": "system record + /now URL + optional Ed25519 signature over the definition (§31.1)"
    },
    {
      "name": "get-system",
      "method": "GET",
      "path": "/v1/systems/{id}",
      "desc": "Retrieve a stored system definition.",
      "input": {
        "id": "string"
      },
      "output": "system record"
    },
    {
      "name": "system-now",
      "method": "GET",
      "path": "/v1/systems/{id}/now",
      "desc": "Current time in a stored custom system (+ world calendar).",
      "input": {
        "id": "string"
      },
      "output": "system_time + reference instant + calendar"
    },
    {
      "name": "list-systems",
      "method": "GET",
      "path": "/v1/systems",
      "desc": "List all stored custom systems.",
      "input": {},
      "output": "system ids"
    },
    {
      "name": "transform-path",
      "method": "GET",
      "path": "/v1/path",
      "desc": "Route between two systems/timescales in the transform graph (§13-14; star graph today).",
      "input": {
        "from": "system id or unix|utc|posix",
        "to": "…"
      },
      "output": "path + hops + lossless"
    },
    {
      "name": "create-group",
      "method": "POST",
      "path": "/v1/temporal-groups",
      "desc": "Persist a Temporal Group — a named set of members (\"utc\"|\"posix\"|\"tai\"|\"gps\"|\"tz:<IANA>\"|<system id>). Re-posting the same id bumps its version.",
      "input": {
        "id": "group:project-alpha",
        "members": [
          "utc",
          "tz:Asia/Taipei",
          "user:game_world"
        ],
        "owner": "string?"
      },
      "output": "group record + expand URL + optional Ed25519 signature over this version (§31.1)"
    },
    {
      "name": "get-group",
      "method": "GET",
      "path": "/v1/temporal-groups/{id}",
      "desc": "Retrieve a Temporal Group definition.",
      "input": {
        "id": "string"
      },
      "output": "group record"
    },
    {
      "name": "list-groups",
      "method": "GET",
      "path": "/v1/temporal-groups",
      "desc": "List all stored Temporal Groups.",
      "input": {},
      "output": "group ids"
    },
    {
      "name": "expand-group",
      "method": "POST",
      "path": "/v1/temporal-groups/{id}/expand",
      "desc": "THE CommonInstant Web flagship: project ONE instant across every member of a group — E(I*, G) = {τ1,...,τn}, \"One Instant, Many Systems\". Default instant is now; pass instant_id to align on a previously-registered I*, or an explicit value+encoding.",
      "input": {
        "instant_id": "string?",
        "value": "string?",
        "encoding": "string?"
      },
      "output": "instant + members[] (each with its local representation)"
    },
    {
      "name": "create-workspace",
      "method": "POST",
      "path": "/v1/workspaces",
      "desc": "Phase 5 Step 1 — Shared Workspace: bundle existing system/group ids under one shareable id for team/multi-agent coordination. NO accounts, NO access control (whoever can reach this API can also read/overwrite it, same as any system or group) — a namespacing convenience only. Re-posting the same id bumps its version.",
      "input": {
        "id": "workspace:project-alpha",
        "name": "string?",
        "systems": [
          "user:game_world"
        ],
        "groups": [
          "group:project-alpha-tz"
        ],
        "owner": "string?"
      },
      "output": "workspace record + expand URL + optional Ed25519 signature over this version (§31.1)"
    },
    {
      "name": "get-workspace",
      "method": "GET",
      "path": "/v1/workspaces/{id}",
      "desc": "Retrieve a Shared Workspace definition.",
      "input": {
        "id": "string"
      },
      "output": "workspace record"
    },
    {
      "name": "list-workspaces",
      "method": "GET",
      "path": "/v1/workspaces",
      "desc": "List all stored Shared Workspaces.",
      "input": {},
      "output": "workspace ids"
    },
    {
      "name": "expand-workspace",
      "method": "POST",
      "path": "/v1/workspaces/{id}/expand",
      "desc": "Resolve every member system AND every member group's members, all at one shared instant, in a single call — a workspace-scoped generalization of expand-group. Default instant is now; pass instant_id or an explicit value+encoding.",
      "input": {
        "instant_id": "string?",
        "value": "string?",
        "encoding": "string?"
      },
      "output": "instant + systems[] + groups[] (each group carries its own resolved members[])"
    },
    {
      "name": "get-current-user",
      "method": "GET",
      "path": "/auth/me",
      "desc": "Phase 5 Step 2 — read the caller's own account, if the ctcl_session cookie identifies an active session (browser-only; requires a prior human sign-in via /auth/google/start or /auth/github/start, there is no programmatic/agent login). 401 if not signed in.",
      "input": {},
      "output": "id + email + name + avatar_url + providers[] + created_at"
    },
    {
      "name": "sign-in",
      "method": "GET",
      "path": "/auth/{provider}/start",
      "desc": "Browser-only redirect into Google or GitHub's OAuth consent screen (provider = google|github). Not an API call an agent makes directly — a human follows this link, then lands back with a session cookie. Exists solely to make Shared Workspace ownership (§Phase 5) real; nothing else on CTCL requires it.",
      "input": {
        "provider": "google|github (path)",
        "redirect": "string? (path to return to after sign-in, default /)"
      },
      "output": "302 redirect"
    },
    {
      "name": "inspect-boundary",
      "method": "POST",
      "path": "/v1/boundaries/inspect",
      "desc": "Proactive pre-flight check (§5.6): is this local time / custom-system state safe? Unlike /v1/convert, never errors — always returns a status: normal|gap|fold (timezone) or normal|pause|rate_change (system), plus upcoming DST transitions within a window.",
      "input": {
        "timezone": "IANA?",
        "local_value": "naive local datetime string?",
        "window_hours": "number? (default 48)"
      },
      "input_alt": {
        "system_id": "string?",
        "value": "string?",
        "encoding": "string?"
      },
      "output": "status + safe + detail"
    },
    {
      "name": "resolve-temporal-context",
      "method": "POST",
      "path": "/v1/resolve",
      "desc": "resolve_temporal_context (§6): map an ambiguous input (city name, common alias, tz abbreviation) to IANA timezone candidates with confidence. NEVER silently picks one when genuinely ambiguous (e.g. \"CST\"). Free-form natural-language time phrases are explicitly out of scope — honest empty result, not a guess.",
      "input": {
        "input": "string (e.g. 'Taipei', '台北', 'CST', 'Asia/Tokyo')"
      },
      "output": "candidates[] (context_id, confidence, source) + scope_note"
    },
    {
      "name": "plan-shared-instant",
      "method": "POST",
      "path": "/v1/planner/shared-instant",
      "desc": "plan_shared_instant (§7): I* = argmax_I U(I | constraints). A demonstration of CTCL-native constraint solving over a bounded search window, NOT a full meeting-scheduler SaaS. See GET /v1/planner/constraint-types for what's honestly supported (no external data feed = declared unimplemented, not faked).",
      "input": {
        "window": {
          "from": "unix_s",
          "to": "unix_s",
          "step_s": "number? (default 900, max 1000 samples)"
        },
        "constraints": [
          {
            "type": "weekday_hours|avoid_window|prefer_window|min_lead_time|system_not_paused|market_hours",
            "weight": "number? (default 1)"
          }
        ]
      },
      "output": "best + alternatives[] (unix_s, score, satisfied/violated/unsupported constraints) + explanation"
    },
    {
      "name": "constraint-types",
      "method": "GET",
      "path": "/v1/planner/constraint-types",
      "desc": "Catalog of planner constraint types and which are actually implemented.",
      "input": {},
      "output": "types + which are implemented"
    },
    {
      "name": "validate",
      "method": "POST",
      "path": "/v1/validate",
      "desc": "Validate a time value; returns warnings (POSIX-vs-UTC leap drift, out-of-range).",
      "input": {
        "value": "string",
        "encoding": "unix_s|…",
        "timescale": "utc|posix?"
      },
      "output": "valid + warnings + canonical_unix_ns"
    },
    {
      "name": "transform-types",
      "method": "GET",
      "path": "/v1/transforms",
      "desc": "Catalog of transform types (§12): identity, offset, linear_rate, piecewise, paused_clock (active-time), …",
      "input": {},
      "output": "types + which are implemented"
    },
    {
      "name": "version",
      "method": "GET",
      "path": "/v1/version",
      "desc": "Versions, leap table, precision tiers (§35), trust tiers (§36), rate-limit policy (§38).",
      "input": {},
      "output": "versions + tiers"
    },
    {
      "name": "pubkey",
      "method": "GET",
      "path": "/v1/pubkey",
      "desc": "Ed25519 public key (§31) — verify a /v1/now or registered-instant signature is authentic (not forged) and, optionally, not stale (replay check). SDK: verifyInstant(inst, {maxAgeMs}).",
      "input": {},
      "output": "alg + key_id + public_jwk"
    }
  ],
  "memory_contract": "For long-term memory: store instant_id + timescale + encoding + source_quality (do not store only a bare number). Distinguish event / write / recall instants (§10.4, §23).",
  "not_a": [
    "universal clock authority",
    "timing/NTP replacement",
    "guaranteed ns-accurate global sync"
  ],
  "mcp": {
    "endpoint": "https://commoninstant.org/mcp",
    "transport": "Streamable HTTP (stateless — no session id)",
    "note": "11 MCP tools share REST handlers, including ctcl.attest_now (non-persistent signing) and ctcl.register_instant (public KV write). No tool grants identity, enrollment, or T3/T4 time authority. Trigger/WakeEvent/Agent-Wake capability remains Local-MCP-only."
  },
  "whitepaper": "CTCL_Agent_Time_API v0.1 (Neo.K / EveMissLab)"
}
