1. 30 Sep, 2026 3 commits
    • Stefy Lanza (nextime / spora )'s avatar
      characters/voices: accept /v1/files paths and sha256 upload ids as media · be1ecdf4
      Stefy Lanza (nextime / spora ) authored
      Motus request 3. The character and voice extractors decoded media with their own
      helpers, which took base64, data: URIs and http(s) URLs but not the
      /v1/files/... paths compose accepts — so a client had to inline every source clip
      as base64 (a third larger) even when the server already held the file it had
      uploaded minutes earlier.
      
      - codai/compose/media.py: one resolver for every accepted reference —
        blob_path() for a sha256: upload id, local_path() for that or a /v1/files path
        (traversal-checked), fetch_bytes() for the endpoints that want bytes; a file we
        hold is read from disk, never fetched over the loopback.
      - characters._decode_source and voice_clone._decode_b64_or_url now delegate to
        it, which also gives POST /v1/characters and PATCH add_images the same
        references (they only base64-decoded before), and _decode_audio takes the
        stored extension from the CONTENT rather than the caller's claim (a
        data:audio/mpeg URI holding a wav was written as .mpeg).
      - uploads.find_blob() reuses media.blob_path so there is one lookup, not two.
      - A bare server path stays refused; a missing blob is a 400 naming the problem.
      - docs/video-compose.md lists the endpoints that share the resolver;
        tests/test_compose.py +2 (every reference form, and a character saved from an
        upload id).
      Co-Authored-By: 's avatarClaude Opus 5 (1M context) <noreply@anthropic.com>
      Claude-Session: https://claude.ai/code/session_01B7EnDW6RSd2nhEPZMzMkqi
      be1ecdf4
    • Stefy Lanza (nextime / spora )'s avatar
      upgrade: fall back to the public mirror when the default remote is unreachable · f32a6c6c
      Stefy Lanza (nextime / spora ) authored
      `coderai-docker --upgrade` was unusable: git.nexlab.net's certificate expired on
      2026-09-15, the clone failed, and the script gave up — although the same
      production branch sits on the public GitHub mirror. Nobody running the published
      image has a stake in that host, so an unreachable default is now a detour, not a
      dead end.
      
      - packaging/linux/launcher/coderai-upgrade: clone_from() per remote; a connection
        /TLS/DNS failure on the DEFAULT remote retries the mirror and logs both the
        reason and the source it ended up using. A repo the operator named
        (--upgrade-repo / CODERAI_UPGRADE_REPO) or an SSH-key clone is never silently
        replaced, and a ref that does not exist stays an error — papering over that
        with the mirror would install the wrong code.
      - Two bugs found while testing it, both silent:
        * `if ! cmd; then rc=$?` captured the status of the negation (0 on failure),
          so the fallback branch could never run;
        * reqs_content() ran under `set -o pipefail` with a `[[ -f ]] && grep` group,
          so a tree without packaging/common/requirements-oci.txt (or with no deps at
          all) aborted the upgrade one line after "upgrading x -> y", with no message.
      - tests/test_upgrade_launcher.py: the real script against local git repos — no
        network — for the healthy default, the fallback, the explicit repo, a missing
        ref and an up-to-date install.
      
      The certificate itself is on the host serving git.nexlab.net (94.23.108.54, not
      lisa) and still needs renewing there.
      Co-Authored-By: 's avatarClaude Opus 5 (1M context) <noreply@anthropic.com>
      Claude-Session: https://claude.ai/code/session_01B7EnDW6RSd2nhEPZMzMkqi
      f32a6c6c
    • Stefy Lanza (nextime / spora )'s avatar
      compose: POST /v1/video/compose and POST /v1/files/upload (v0.2.22) · 5abbb81d
      Stefy Lanza (nextime / spora ) authored
      CoderAI could make every piece of a short video and nothing turned the pieces
      into a reel — assembly needs ffmpeg and two facts only the server has (how long
      the narration it just synthesised is, and when each word falls), so a detached
      client cannot do it. Requested by the Motus project over the HTTP API.
      
      - codai/api/compose.py: scenes -> one uploadable video. Scene length = narration
        + padding (min_duration floor), visuals split it evenly; async job with
        stage/progress/message/warnings, cancel (the ffmpeg child is killed), a queue
        that reports its position, and a blocking form for tests. Narration, music and
        word timings come from this server's own endpoints, called on a loop this
        module owns — never the request's loop, which may be closed before the render
        needs it. 400 names the offending scene/field; 501 when a sub-feature has no
        model (music.generate, timing=stt, TTS for narration) or ffmpeg is missing.
      - codai/compose/render.py: one normalised clip per visual (so a failed visual
        becomes a gradient and a warning instead of a lost render), concat or xfade
        that preserves the total duration, narration padded per scene and
        loudness-normalised, music looped/faded/ducked with sidechaincompress, burned
        captions + overlays with the final H.264 High/AAC/+faststart encode, thumbnail.
      - codai/compose/captions.py: word timings from STT aligned onto the CALLER's
        words (a mis-heard word never reaches the screen) or estimated; line breaking;
        ASS with six presets inside a 10%/6% safe area; SRT/VTT with the same text.
      - codai/compose/media.py: resolve a URL / /v1/files path / data URI / base64
        (never a server path), probe with ffprobe, resolve fonts through fontconfig.
      - codai/api/uploads.py: POST /v1/files/upload, content-addressed by sha256 with
        GET /v1/files/blob/{hash} so a client can skip a re-upload; type decided by
        content, not by the client's claim.
      - compose and uploads are pinned local in the capability gateway (a pod has
        ffmpeg but not this install's models or files); both advertised in the
        capability document; caption fonts (Montserrat/Inter/Noto CJK) added to the
        three image builds.
      - docs/video-compose.md; tests/test_compose.py (30, real ffmpeg, no model/GPU).
      Co-Authored-By: 's avatarClaude Opus 5 (1M context) <noreply@anthropic.com>
      Claude-Session: https://claude.ai/code/session_01B7EnDW6RSd2nhEPZMzMkqi
      5abbb81d
  2. 20 Sep, 2026 2 commits
    • Stefy Lanza (nextime / spora )'s avatar
    • Stefy Lanza (nextime / spora )'s avatar
      cluster: mDNS discovery with a shared token, prefix-cache routing, Prometheus... · 0d4a338b
      Stefy Lanza (nextime / spora ) authored
      cluster: mDNS discovery with a shared token, prefix-cache routing, Prometheus /metrics + per-key usage, node logs and re-push on return, GGUF row split, cosign-signed images
      
      - codai/cluster/discovery.py: _coderai._tcp announce + browse (zeroconf), HMAC
        fingerprint of cluster.token as membership; members auto-join as nodes,
        listed nodes with a blank key get the shared token; nodes and engines accept
        the cluster token (front /cluster/*, engine BearerAuth); env overrides for
        capability images (CODERAI_CLUSTER_TOKEN/DISCOVERY/NODE_NAME/ADVERTISE_HOST);
        coderai-docker --host-network
      - frontproxy/affinity.py + router prefer=: a conversation goes back to the
        engine/node that served it when the model is resident in several places;
        engine_for_model now picks the least busy holder
      - frontproxy/metrics.py: /metrics (requests per key/model/kind/status/engine,
        engines/nodes up, VRAM, in-flight, RPC, discovery, RunPod spend), usage
        tables on the Cluster page, server.metrics_public
      - node logs: /cluster/logs on the node, /admin/api/cluster/logs on the head,
        log viewer on the Cluster page; a node that comes back gets its assigned
        models pushed again
      - per-model split_mode=row (llama.cpp tensor parallel over local + RPC devices);
        vLLM TP may span nodes (documented)
      - packaging/sign-images.sh + packaging/cosign.pub: all 21 GHCR images signed
      - docs/cluster.md §§ discovery, 7 prefix routing, 9 operating, 10 accelerators
        evaluation; tests/test_cluster_ops.py (11)
      Co-Authored-By: 's avatarClaude Opus 5 (1M context) <noreply@anthropic.com>
      Claude-Session: https://claude.ai/code/session_01FKm7Z56iKjHgNkHc6VhWKz
      0d4a338b
  3. 19 Sep, 2026 17 commits
  4. 18 Sep, 2026 6 commits
  5. 17 Sep, 2026 7 commits
  6. 16 Sep, 2026 5 commits