No description
  • C# 87.8%
  • HTML 5.6%
  • JavaScript 3.4%
  • Python 2.1%
  • CSS 1%
  • Other 0.1%
Find a file
scarlet 459b1037fd
Some checks are pending
CI / shell-eval (push) Waiting to run
CI / test (push) Blocked by required conditions
CI / image (push) Waiting to run
Build and Push Docker Image / build-and-push (push) Waiting to run
CI / build (push) Has started running
feat: Phase 4b-b — guarded browser networking (#87)
Phase 4b-b adds the browser's connection boundary under ADR 0025 while Browser tools and owner controls remain deferred.

## What's in

- A loopback SOCKS5 CONNECT gateway per worker resolves once, rejects an entire DNS answer set containing any forbidden address, then dials a checked numeric endpoint. HTTP(S), redirects, frames, resources and WS(S) retain Chromium's TLS, cookies and streaming.
- Browser and Web compile the same public-address rules while retaining separate transports. Both consume the existing deployment infrastructure denials; private SearXNG configuration grants Browser no exception.
- Chromium uses one mandatory proxy, loopback bypass subtraction, suppressed browser DNS, disabled QUIC and the headed WebRTC UDP restriction. Native startup/session material is cleared before the host restores its bounded HTTP(S) checkpoints.
- A refused navigation cancels Chromium's pending native load before resetting to blank. The same logical tab retains its password history and output refusal state; repeated error navigations cannot poison the next scan.
- The final-image runner uses a dedicated internal network without an external route so ICE has a real interface. Container/network cleanup is independent and preserves the original failure status.
- ADR, plan and operator guidance updated. No runtime tools, mounts, published artifacts, credentials UI or new familiar state; the app seed stays unchanged.

## Tests

- 90 added tests; 7,457 total. Serial build has zero warnings/errors; full suite passes locally and in UTC.
- SOCKS tests assert fragmented negotiation, CONNECT-only behavior, private/literal/mixed DNS rejection before any dial, rebinding and approved-address fallback, production numeric-only connection semantics, opaque end-to-end TLS, concurrency/deadline bounds, active-tunnel teardown and late connector disposal.
- Worker guard theories cover canonical loopback endpoints and refusal of invalid ports, alternate hosts, local-file/other schemes, user information and unlisted internal URLs. Configuration tests assert shared infrastructure denials in both adapters and explicit normalized copies, including IDNs and mapped IPv4. Profile tests assert native restore removal and WebRTC override removal without destroying unrelated preferences.
- 98 final-image checks pass against disposable public-shaped fixtures, with a diagnostic connector replacing only exact approved sockets. Includes actual private frame/resource/fetch/WS(S) attempts, redirects/literal bypass, self-signed TLS rejection with valid HTTP/WS positive controls, restored DNS changes, an explicitly armed native-file control with a unique uncached image response/load acknowledgment, actual blank-reset assertions, repeated recovery with preserved password scrubbing, and fatal restore cleanup without a fallback navigation.
- Independent static review approved the complete diff. Independent executable review approved the final state after establishing passing baselines and killing mutations for mixed DNS, hostname re-resolution, effective loopback bypass, ignored TLS certificate errors, removed WebRTC policy, missing blank reset, old fatal-restore fallback, disabled native-image control and stale restored checkpoints. Removing the explicit bypass option alone was equivalent because Playwright supplies the same handling.
- Runner failure injection confirms network cleanup still runs if container removal fails and preserves the original exit code.

## Validation limits

The executable review passed three consecutive complete 98-check runs and a final clean-image repeat. A preceding clean-image attempt failed early near fixture login with an unclassified IOException; that failure remains unexplained. The revised native control passed every completed review run.

One local UTC run hit an existing Blazor background-health render timeout while browser checks were running; the isolated test and complete UTC rerun passed without UI changes.

Local browser verification used the Release-published app over the cached image containing the same pinned Chromium/runtime dependencies; CI builds the complete Dockerfile and runs the same check. This is local container evidence, not a new deployment-VM run.

STUN suppression is mutation-verified on the internal NIC. TURN's zero-connection observation lacks a positive control and does not alone prove TCP suppression. This is browser application policy, not an OS egress firewall. Routing disables Chromium's HTTP cache; cookies and site storage remain persistent. Gateways allow 32 connections, a 10-second handshake/connection deadline and a 30-second bidirectional idle timeout, so quiet WebSockets may reconnect.

Co-authored-by: schattenan <schattenan@kagaku.eu>
Reviewed-on: #87
2026-10-24 19:04:31 +02:00
.agents/skills/browser-test feat: 2b — redirections and tee (#84) 2026-10-24 15:51:00 +02:00
.claude/skills feat: add seeded browser testing skill and launcher (#34) 2026-10-22 20:41:14 +02:00
.config feat: Phase 0a — the repository skeleton stands up (#2) 2026-10-17 15:01:07 +02:00
.github fix(ci): stop the image job leaking a 2.5 GB image per run (#60) 2026-10-23 15:56:14 +02:00
deploy feat: Phase 4b-b — guarded browser networking (#87) 2026-10-24 19:04:31 +02:00
docs feat: Phase 4b-b — guarded browser networking (#87) 2026-10-24 19:04:31 +02:00
external feat: B7 — adopt the public Kagaku.UI customization contract (#86) 2026-10-24 19:04:06 +02:00
src feat: Phase 4b-b — guarded browser networking (#87) 2026-10-24 19:04:31 +02:00
tests feat: Phase 4b-b — guarded browser networking (#87) 2026-10-24 19:04:31 +02:00
.dockerignore feat: Phase 0c — CI and the container (#4) 2026-10-17 16:36:24 +02:00
.gitattributes feat: Phase 0a — the repository skeleton stands up (#2) 2026-10-17 15:01:07 +02:00
.gitignore feat: Phase 0a — the repository skeleton stands up (#2) 2026-10-17 15:01:07 +02:00
.gitmodules feat: Phase 0a — the repository skeleton stands up (#2) 2026-10-17 15:01:07 +02:00
AGENTS.md feat: B7 — adopt the public Kagaku.UI customization contract (#86) 2026-10-24 19:04:06 +02:00
Directory.Build.props feat: Phase 0a — the repository skeleton stands up (#2) 2026-10-17 15:01:07 +02:00
Directory.Packages.props feat: Phase 3d-a — SearXNG-backed Web capability (#58) 2026-10-23 14:47:28 +02:00
README.md docs: target CalDAV and Google Calendar for the first version (#42) 2026-10-22 23:03:49 +02:00
Shikigami.slnx feat: Phase 3d-a — SearXNG-backed Web capability (#58) 2026-10-23 14:47:28 +02:00

Shikigami

A single-user, self-hosted home for familiars — AI companions you define yourself, each with a persona of its own, a memory it keeps in files, skills it writes for itself, routines it runs on its own, and hands that reach a real browser and your mailbox. A Blazor Server app on .NET 10, like its siblings Kagura, Tsumugi and Orihon; every model call goes through OpenRouter.

Architecture decisions live in docs/adr/README.md; requirements and user stories follow them. docs/PROJECT_PLAN.md ticks the slices that have landed. Building and testing: AGENTS.md, Running it. Browser verification with isolated sample data: browser-test skill.

Shikigami (式神) are the spirits an onmyōji binds to serve beside them — a familiar, not a butler. In this app a familiar can be anything you make it: a goof-off catgirl who watches your mailbox and tracks your figure orders, a calm Honkai: Star Rail strategist who follows the leaks, a Pokémon companion who remembers where your Gen 2 run stopped. Each one lives in its own small file system — persona, memory, skills, notes, routines, chats — that it works in through a familiar shell, and that you can open and edit in the same app.

What it is not

  • Not a coding agent or a productivity harness: no real shell, no machine of its own, no repository access.
  • Not a gated agent: there are no approval dialogs. Everything a familiar does lands in its activity log.
  • Not shared memory: familiars never read each other's files.

Prerequisites

  • .NET SDK 10.0+
  • Access to the vendored submodules on git.kagaku.eu (TeamAI org): OpenRouter.Net, Kagaku.UI

Layout (ADR 0001, 0003)

Project Responsibility
src/Shikigami.Kernel Technical primitives (Result<T>, guards). References nothing.
src/Shikigami.Domain Familiars, chats, messages, the file model, routines' schedule arithmetic. Pure.
src/Shikigami.UseCases Application layer: use cases, ports, the familiar runtime, the shell interpreter.
src/Shikigami.Infrastructure Core driven adapters: EF Core SQLite, the agent loop over OpenRouter.Net, Playwright, backups.
src/Shikigami.BlazorAdapter The UI: the cast, chats, the file browser, the activity timeline, settings.
src/Shikigami.Server ASP.NET host + composition root.
tests/* Unit, integration and component test projects.
external/* Vendored libraries as git submodules.
docs/ Architecture overview, project plan, requirements, ADRs, user stories.

The capability architecture adds a small Contracts library and bundled Mail, Calendar, Images and Feeds libraries through the capability track and their feature slices. Each owns private bookkeeping per familiar; the host retains settings/secrets, published virtual files and backup coordination. These projects are planned work, not an external plugin loader.

Conventions

  • .slnx solution format; Directory.Build.props + Directory.Packages.props (central package management).
  • net10.0, nullable + implicit usings on, warnings-as-errors, deterministic, invariant globalization.
  • Versioning via MinVer (v-prefixed tags).
  • CI on Forgejo Actions (.github/workflows/); container image published to git.kagaku.eu/teamai/shikigami, deployed as a Portainer stack behind the host's Caddy (deploy/).
  • Docs: docs/adr/ (Nygard ADRs), docs/REQUIREMENTS.md (the tracker), docs/stories/ (user stories).