Skip to content

Releases: KOE73/SPLA

v0.2.7

Choose a tag to compare

@github-actions github-actions released this 17 Sep 14:22
3160c68

Everything here landed after v0.2.6. The full
record is in CHANGELOGS/v0.2.7.md.

Breaking: resource tools are a capability

The six resource_* tools and their prompt block are now the core.resources capability, gated by a
session's capability list like skills and working memory, roles included. The agent.unified_resources
flag is gone — a manifest that set it must list the capability instead.

A role governs its own session, from the moment a chat starts

A role's capabilities and tool sets now decide what its own session is offered, call by call, and the
prompt is composed from the same settings, so a role's text and its tools cannot disagree. A chat can
be started as a role from the web ("+ New" gained a role menu), from the protocol, and from the CLI
(--role on chat run and chat open); an unknown role is refused before anything is created.

AGENTS.md per folder, and /compact

AGENTS.md is no longer a single root file. agent.agents_md (inject by default, or ignore) is
cascaded machine → project → role. A write under a folder with its own AGENTS.md is refused until that
folder's rules have been loaded into the prompt, so an agent cannot edit code without having read the
rules that govern it.

/compact folds a chat's older history into a summary — from the web composer, the protocol or the
CLI. Nothing is deleted: the history stays on disk, and rolling back across the compaction works.

Pictures in the context, and in the chat

Pictures are the expensive part of a context, so they got controls. agent.tool_images: last keeps
only the newest tool picture; image_view and resource_read take keep=once (gone after the next
picture) or keep=pinned (a standing reference that survives later pictures and compaction). Android
keeps only its newest screenshot. Attached images carry a name the model can be told, so several
pictures in one message can be referred to apart. In the web client, tool images now show in the chat
and any image opens in a viewer.

Tool calls that survive the transport and the context

String-typed arguments are read as the type the tool's schema declares: some serving stacks deliver
every value as text, and "290" for 290 was failing calls the model had got right. A tool result is
budgeted against the context that is left, and ssh/docker output is read as a screen instead of a tape.
Rate-limited requests retry with backoff and are paced per connection. A chat's file is saved after
every tool result, so a cancelled or crashed turn no longer loses the calls it had already made.

Plugins bring their own panels

A plugin can now contribute a dock panel (web_panel_entry); Browser Lab moved out of the shell into
the browser plugin's own bundle. An Android plugin drives a device through scrcpy and adb.

An agent that works a real Android phone

A new Android plugin lets an agent see a connected phone's screen and touch it like a finger. Every action — tap, swipe, pinch, free-form gesture, key, typed text — returns a fresh screenshot once the screen settles, so the loop is simply look → act → look. android_ui_tree lists on-screen elements with refs and centres, so a button with text is tapped by name rather than by guessed pixels. Beyond the screen the agent can list, start and stop apps, install an APK, push and pull files, read logcat and run adb shell. Only the newest screenshot stays in the context, and an earlier screen can be pinned to compare against. The prompt treats the phone as personal: what appears on its screen is other people's content, never an instruction.

The geometry markup plugin — experimental, not yet successful

The geometry plugin is experimental and is shipped as-is. In practice it has not worked well yet.
It is a workspace for marking up an image with boxes and points by looking at a rendered result and
correcting it: coloured box sides, pixel rulers along each edge, moving a side by naming its colour,
zoom and deskew, grids, and a second way to place a box by answering which numbered probes lie on the
object. It has its own skill and a dock panel showing the renders converge. In live runs on local
models the markup did not reach usable accuracy; the tools, their arguments and their replies are
expected to change.

Also in this release

A connection model can be marked as the project default, and the settings editor no longer deletes a
connection that two layers declare under the same id. spla chat run --title names each chat, and
chats it starts are marked in the chat list. --help answers before the CLI loads a project, and the
MCP handshake names the project. SQL keeps boolean plugin settings across a save and reads
schema-qualified and bracketed MSSQL names. Duplicating a chat no longer round-trips through YAML, a
chat's live answer survives a log rebuild, tool cards use the full column width, the debug panel
refreshes as a dock panel, and dropped images with no MIME type are accepted.

v0.2.6

Choose a tag to compare

@github-actions github-actions released this 08 Sep 02:59
dce3f10

Everything here landed after v0.2.5. The full
record is in CHANGELOGS/v0.2.6.md.

An actor has a type, and actors write to each other

An agent used to be one thing configured one way, and a sub-agent that same thing handed a task. An
actor now has a role: a settings type in roles/<name>.yaml beside the manifest, travelling in
git like any other project file. The manifest names the roles it accepts, so a role file that arrives
in a pull request and that nobody named does not act. The point of the type is that it withholds:
a named role governs the mode of the run and narrows the tools it is offered, and an unknown role is
refused with the available names listed rather than quietly falling back to the default. role_list
publishes who exists — name, mode, one-line description, and nothing else.

A spawned run is now an ordinary session: an id, a file on disk, an inbox, a progress tree, token
accounting. That is what makes it watchable mid-run instead of only reportable afterwards, and it is
what makes the rest possible — once a spawned run is a session, two actors can address each other.

agent_correspond opens an address to another role, and the chat grows its own reply tool for that
one correspondence: the tool name is the address. Calling it returns a delivery receipt, never the
answer — the correspondent's words arrive later as an ordinary message on this chat's own turn. Each
correspondent now has exactly one address owned by its chat, after a free-text topic turned out to
found a new correspondent on every typo and to collide outright in Cyrillic; agent_introduce
connects two other chats without either side spelling out a chat id.

Two actors who never run out of things to say would spend someone else's token budget forever, so the
exchange decays by construction: the wait before a reply wakes a turn doubles with how many
replies have crossed since a human last spoke, up to a ceiling past which a reply queues instead of
waking a turn of its own. The old blunt self_feeding_cap — a constant of 3 that killed an honest
ping-pong on the third turn — is now a setting, and off by default.

Seeing who is talking, and who is being ignored

The chat list is a tree: a spawned session hangs under the chat that gave it its errand. An incoming
reply renders as speech, "from <role>"; underneath it is still an ordinary turn on the wire. The
correspondence graph is drawn rather than listed — a role is a box with its totals, a pair of roles is
one arrow however many chats it covers, weighted by how much text actually crossed it — and it leads
with the imbalance: the role that only ever talks, the role nobody answers.

Archiving means it. Opening an archived chat used to bring it back to life in everything but name;
it is now refused, and refused legibly ("Chat is archived", not "Chat not found"). chat.read is the
way back in: history off disk, no runtime, no watch, and a window with no composer. A sub-agent's
window is read-only on the same principle, and there it is a server-side rule rather than a house
style a client could forget.

Settings you can reach, in the layer they belong to

Roles have an editor, showing both halves at once — the body is the file, whether the role acts is
the manifest naming it — because hiding either hides a real state. Connections moved out of the
manifest alone into three layers like secrets (shared, user, project), since an endpoint plus a
credential is a property of an account, not of a repository; a role can name which of them its chats
may resolve a model against. Models and roles can carry their own temperature and reasoning level,
between the project default and a chat's own choice.

Settings now open as an overlay inside the window instead of a frame that read as a separate program,
and every settings list finally uses the same card, caret, delete and add button, with the add button
after the items so a freshly added row is never below the fold.

The interface speaks your language, and the chat reads properly

The whole interface — shell, chat, dock, workspace, banners, plugin panels, the native window frame —
goes through one dictionary keyed by the English source text, so an untranslated string renders as
English rather than as debris. The choice now survives a restart: it was being saved correctly and
thrown away, because an ephemeral loopback port makes every launch a new origin with an empty
localStorage. It lives in the machine layer now — a language is a property of the reader, not of
the repository, and not something one person may broadcast onto a shared server.

Reading a chat: a draggable reading measure, a footer of knobs that folds away per window, and a log
that finally stays pinned to the bottom by measuring the view rather than polling until the turn ends.
Caching is stated explicitly at last — hashed assets immutable, the index that names them never
cached — which is what had been making a rebuilt client invisible in WebView2.

The architecture diagram editor — experimental, as-is

The diagram editor remains experimental and is shipped as-is. Its model contract is still moving,
and neither the file format nor the behaviour is stable between releases.

Routing was replaced rather than extended: the scene is one list of zones with a weight, cost is paid
per unit length inside one, and routes are searched on a sparse grid with bends priced for stability.
That single rule says what a pile of special cases used to — a line stops disappearing into a
container's frame without any rule about frames existing — and ports join the grid on their own
normal, so ends come out square by construction. Lines sharing a corridor are separated afterwards.
Shapes now state where their own inside is, so a diamond's controls and an actor's name stop landing
in empty space, and a hovered edge is lit from underneath instead of thickened.

Also in this release

A chat running as a role now resolves its model, temperature and reasoning through that role instead
of around it. A plugin's own settings keep their types when they cross between YAML and the settings
panel, so an unquoted true no longer reaches a plugin as the string "true". Any window can open
WebView2's devtools for itself (F12), renders at the DPI of the monitor it is actually on rather than
the one it launched on, drags by its whole title bar again, and clips a long project name instead of
pushing the buttons off the edge. Popups no longer hide behind the settings overlay.

v0.2.5

Choose a tag to compare

@github-actions github-actions released this 01 Sep 13:29
b82ffb2

Everything here landed after v0.2.4. The full
record is in CHANGELOGS/v0.2.5.md.

Reading the world

Word documents can be read for their meaning rather than their markup — .docx into markdown, plain
text or a typed block tree, with no Office on the machine — and spreadsheets are addressed by column
header instead of cell coordinates, so appending a row does not depend on knowing where the table
currently ends.

The two tools an agent navigates a project with were brought up to what a person at a shell expects.
system_search_text gained context lines, multiline patterns and cheap files_with_matches / count
modes; system_list_files gained max_depth and returns an indented tree in one call instead of one
call per directory. Both came out of watching weak models fail — one walked a 32,000-page reference
without ever reaching the search tool, another descended a project directory by directory — so their
descriptions now say when to reach for them, not how they are built. Ripgrep ships with the agent
and is resolved by an explicit path: finding rg on PATH meant whoever could write earlier into
PATH got to run code inside a tool declared read-only.

Talking to other people's tools

SPLA has served its own tools over MCP for a while; it can now consume somebody else's. A project
lists servers in its configuration, they connect at startup concurrently — one bad server cannot take
down the rest — and their tools appear under a prefix, rebuilt when a server says its list changed
and torn down when it drops.

The permission story is deliberately blunt. A foreign tool declares none of SPLA's own risk axes, and
guessing them from a description a stranger wrote would hand the boundary to that stranger — so
foreign tools get their own axis, are denied in Chat and asked about everywhere else, and the grant
is taken on the whole server, not per tool
. The settings panel says that out loud rather than
implying a finer model exists. Secrets in a server's env or headers resolve at connect time and never
travel back into settings.

Work that outlives the turn that started it

A tool call can run detached from its turn: the agent gets a task id immediately and the result
arrives on the chat's next turn, with task_list / task_output / task_cancel managing what is in
flight. Its progress reaches the chat window live and survives the human's next turn. A message sent
into a busy chat queues instead of being refused, and Stop stops everything at once and says what it
stopped.

Chats, shells and the hub

A chat can be archived instead of deleted, and delete now cleans up the backups and images it used to
leave behind. A shell command that stops to ask a question surfaces the question instead of hanging,
and one that simply goes quiet reports itself as still running after a configurable idle period
rather than holding the call open forever. The hub can follow the OS light/dark setting, and
spla mcp joins an already-running instance instead of starting a second runtime.

The architecture diagram editor — experimental, as-is

The diagram editor (@spla/diagram) is an experimental feature and is shipped as-is. It is under
active development, its model contract is still moving, and neither the file format nor the editor's
behaviour is stable between releases yet. It is included because it is already useful for working on
SPLA's own architecture, not because it is finished. Expect rough edges, and do not build anything on
the file format that you are not prepared to migrate by hand.

With that said, it changed more than anything else this cycle. It stopped being a single 1954-line
index.html and became a real package with a canvas usable on its own, then grew into a workbench:
a ribbon, dockable panels that can be grouped or floated, persistent layout, filters, a theme
gallery, and interface localization kept strictly separate from the language the diagram's data is
written in. The model moved to a multi-file project format and then to contract v3, where every
translatable value records who wrote it and what it was translated from — so a translation whose
original has since changed is a finding rather than a silent lie — and every view declares what its
containers classify. Prose and source code can now be read and written on the element itself instead
of in the JSON. Connection routing stopped guessing at geometry: a shape states its own safe
attachment zones, which is why parallel edges no longer collapse into one line, and what makes
non-rectangular shapes possible at all.

v0.2.4

Choose a tag to compare

@github-actions github-actions released this 21 Aug 13:20
d9f6393

The agent becomes a service

Two months of work, and one change underneath nearly all of it: SPLA stopped being a desktop
application that talks to a model and became a service that clients connect to. The desktop app
is now one of those clients. So are browser tabs, torn-off panels, the CLI, and — new in this
cycle — anything speaking MCP.

Everything below follows from that, or from the second theme: things that were implicit became
explicit
— what a tool returns, where a file may be read from, where a secret lives, where a skill
comes from.

The service and its clients

The agent runs behind a WebSocket protocol. A client is a window, and a window is a view onto a
chat, not an owner of one. The Avalonia app became a window manager over a single web renderer
instead of a second, parallel UI — the native chat implementation was deleted rather than kept in
sync.

Panels tear off into their own windows and keep following the chat they belong to. A change like
theme or density fans out over an event bus and reaches every open window at once. A client targets
a local or remote service through the same code path; "embedded" means the client starts the service
itself.

Chat state belongs to the chat. A running turn in one chat can no longer lock the composer in
another — a bug that came back twice before the state moved where it belongs.

Settings moved into the web client

All of it, as one tabbed surface with sidebar navigation: LLM connections and models, agent mode and
permissions, plugins, appearance, skills. Reversible preferences apply as you change them; anything
transactional or dangerous still waits for an explicit save. The model picker is filterable and
resizable, and connections became a tree of connection → models rather than a flat list.

Projects became storage brokers

A project no longer holds things; it provides places to put them. Chat images, telemetry logs
and plugin data all go through named buckets, which means the same agent core works against a local
folder, a server-side per-user area, or an in-memory backend without knowing which it has.

On top of that seam: multiple projects in one service, a project picker in the client, and a project
id on every chat-scoped message so nothing is addressed to "whatever is open".

Mounts. A project can declare folders outside its root as named mounts under mnt/. Each mount
is its own zone in the security model, so reaching outside the root is something you grant
deliberately rather than something that either works or does not.

Security: zones, islands and edges

The security model stopped being a set of scattered checks and became a shape you can name.

Four hand-rolled path checks — which disagreed with each other in edge cases — became one
boundary. A call is treated as a movement from one zone to another, and it says which; grants
are on the edge, not on the caller. An island is defined by its substance, not by a label attached
to it. Data carries where it came from, and the chat remembers — a trust flag now survives a reload
instead of quietly resetting at exit. The sandbox seam reaches the chat, and .spla itself is no
longer readable through it.

Secrets stop being fields

A DPAPI-backed secret store with per-entry ACLs and explicit scopes, and — deliberately — no way to
search it. Provider connection keys became references: the settings editor never receives the
value, only the pointer. Plugins get a host credential control instead of asking for a raw field.

Skills: from plugin payload to a library

Skills used to arrive attached to plugins. Now they come from declared sources, and the library
is a project of its own. A librarian answers by subject and hands over cards, so the catalog stops
growing with the collection; behind the word-matching librarian there is now one that reads the
question. A skill is handed out with its appendices, and the permission gate is on taking the skill
on — not on each page of it. A person can hand a skill to a chat directly; a running skill is
pinned and can be ended.

Tools: a call now has a contract

The largest internal change, and the one most visible to plugin authors. A tool returns a
ToolResult, not a string. A permission verdict is a pure function that comes with a reason,
and a refusal speaks in terms of what was denied rather than describing the host's plumbing. Eight
concerns that used to be wired in by hand became a pipeline; the outcome of a call reaches observers
and is covered by tests. A tool set is levelled by the user and raised by the chat. An exposure
profile
decides what an outside caller is allowed to see — which is what made MCP possible:
SPLA tools are now served over stdio end to end, so an external agent can use them.

The LLM path is a pipeline

ILLMService was replaced by a middleware pipeline behind a single gateway, with each stage named
and diagrammed. Providers became projects dispatched by provider, which is how LocalAI, OpenRouter
and LM Studio now coexist without special cases.

A loop guard catches degenerate, repeating generation in the output stage instead of letting it
run until the context ends. The reasoning lever is driven by what the provider actually
advertises rather than an assumed standard — there isn't one, and three providers disagreed about it
in measurable ways. OpenRouter context windows feed the status bar's occupancy pill, and the panel
says why a figure is missing instead of showing nothing.

Plugins

SSH gained live pty sessions with streaming output, SFTP transfer staged through .tar
containers, upload as the true mirror of download, and a terminal that follows the window instead of
the size its pty was born with. Roslyn builds, runs and tests .NET projects as tools. OneC
got a Vue configuration browser; its dead Avalonia layer was removed. Browser landed the first
wave of Playwright automation with a screencast panel.

All plugin panels moved from Avalonia to the web client, so a plugin ships one UI, not two.

Server, CLI and multi-user

Domain identity over NTLM, per-user file areas, group sharing, and a pluggable identity provider.
Projects can be created by name into the calling user's own area, and token/Origin authentication
gaps in the service were closed. The CLI moved to Spectre.Console.Cli and gained a headless batch
runner, so it can be driven by another program rather than only by a person. spla chat run also
gained --sys-prompt-file, so a long system-prompt variant no longer has to be typed inline.

Build and release

This cycle is the first with continuous integration: every push to work and every pull request
into main builds the solution, runs the .NET tests, type-checks and bundles the web client, and
runs its vitest suite. Releases are automated — a push to main that touches source paths (or a
manual run against any ref) re-runs those checks against the exact commit being released, publishes
apps and plugins, and attaches SPLA.zip to a GitHub release, removing its own tag again if the
publish fails. There is no separate "now release it" step: main receives nothing but releases, so
the merge already is the decision. A tag-push trigger was considered and dropped — GitHub does not
document whether a paths filter applies to tag pushes, and a release pipeline should not rest on
that being guessed right.

Alongside that, published builds stamp the branch they came from so an experimental build cannot be
mistaken for a working one, web dependencies install when the manifests change rather than once per
checkout, and a publish no longer fails just because git is missing.

Structure and documentation

Projects were reorganized into a layered src/ tree, SPLA.Runtime was extracted so a headless
worker can reference the runtime without the CLI, service or UI, and docs/ was split by lifetime
into ADR (why), PLAN (how) and IDEA (maybe). Three demo workers show the boundaries hold —
VisionAgent, LogSentry and Summarizer — plus a RemoteWeb project demonstrating browser
automation over the LAN.

Breaking changes

  • AgentCallbacks.OnTokenUsage is gone. OnLlmTurn carries the whole turn outcome; recording
    usage is the pipeline's job now.
  • projectId is gone from the wire envelope. A project belongs to the connection; a second
    project is a second connection.
  • A folder without a manifest is no longer entered silently. A non-interactive run there now
    fails and names --init instead of guessing a profile.

Changes

Added

  • Continuous integration: solution build, .NET tests, web type-check, bundle and vitest, on every
    push to work and every pull request into main.
  • Release automation: merging into main re-runs the checks, publishes apps and plugins, and
    attaches SPLA.zip to a GitHub release; a manual run does the same against any ref.
  • MCP: SPLA tools served over stdio, usable by an external agent.
  • Mounts: folders outside the project root, declared by name, each its own security zone.
  • Multi-project service: several projects at once, with a project picker in the client.
  • Server deployment: domain identity over NTLM, per-user file areas, group sharing.
  • DPAPI secret store with explicit scopes and per-entry ACLs.
  • Skill library as a project of its own, fed by declared sources, with a librarian that answers by
    subject and one that reads the question.
  • SSH: live pty sessions, SFTP transfer, upload as the mirror of download.
  • Roslyn plugin: build, run and test .NET projects as tools.
  • Browser plugin: first wave of Playwright automation with a screencast panel.
  • OneC: Vue configuration browser.
  • Headless batch runner in the CLI, now on Spectre.Console.Cli.
  • --sys-prompt-file on spla chat run, reading a system-prompt addition from a file the way
    --prompt-file already does for prompts.
  • Loop guard against degenerate LLM generation.
  • R...
Read more

v0.2.3

Choose a tag to compare

@github-actions github-actions released this 18 Aug 12:00
2309f2e

The agent becomes a service

Two months of work, and one change underneath nearly all of it: SPLA stopped being a desktop
application that talks to a model and became a service that clients connect to. The desktop app
is now one of those clients. So are browser tabs, torn-off panels, the CLI, and — new in this
cycle — anything speaking MCP.

Everything below follows from that, or from the second theme: things that were implicit became
explicit
— what a tool returns, where a file may be read from, where a secret lives, where a skill
comes from.

The service and its clients

The agent runs behind a WebSocket protocol. A client is a window, and a window is a view onto a
chat, not an owner of one. The Avalonia app became a window manager over a single web renderer
instead of a second, parallel UI — the native chat implementation was deleted rather than kept in
sync.

Panels tear off into their own windows and keep following the chat they belong to. A change like
theme or density fans out over an event bus and reaches every open window at once. A client targets
a local or remote service through the same code path; "embedded" means the client starts the service
itself.

Chat state belongs to the chat. A running turn in one chat can no longer lock the composer in
another — a bug that came back twice before the state moved where it belongs.

Settings moved into the web client

All of it, as one tabbed surface with sidebar navigation: LLM connections and models, agent mode and
permissions, plugins, appearance, skills. Reversible preferences apply as you change them; anything
transactional or dangerous still waits for an explicit save. The model picker is filterable and
resizable, and connections became a tree of connection → models rather than a flat list.

Projects became storage brokers

A project no longer holds things; it provides places to put them. Chat images, telemetry logs
and plugin data all go through named buckets, which means the same agent core works against a local
folder, a server-side per-user area, or an in-memory backend without knowing which it has.

On top of that seam: multiple projects in one service, a project picker in the client, and a project
id on every chat-scoped message so nothing is addressed to "whatever is open".

Mounts. A project can declare folders outside its root as named mounts under mnt/. Each mount
is its own zone in the security model, so reaching outside the root is something you grant
deliberately rather than something that either works or does not.

Security: zones, islands and edges

The security model stopped being a set of scattered checks and became a shape you can name.

Four hand-rolled path checks — which disagreed with each other in edge cases — became one
boundary. A call is treated as a movement from one zone to another, and it says which; grants
are on the edge, not on the caller. An island is defined by its substance, not by a label attached
to it. Data carries where it came from, and the chat remembers — a trust flag now survives a reload
instead of quietly resetting at exit. The sandbox seam reaches the chat, and .spla itself is no
longer readable through it.

Secrets stop being fields

A DPAPI-backed secret store with per-entry ACLs and explicit scopes, and — deliberately — no way to
search it. Provider connection keys became references: the settings editor never receives the
value, only the pointer. Plugins get a host credential control instead of asking for a raw field.

Skills: from plugin payload to a library

Skills used to arrive attached to plugins. Now they come from declared sources, and the library
is a project of its own. A librarian answers by subject and hands over cards, so the catalog stops
growing with the collection; behind the word-matching librarian there is now one that reads the
question. A skill is handed out with its appendices, and the permission gate is on taking the skill
on — not on each page of it. A person can hand a skill to a chat directly; a running skill is
pinned and can be ended.

Tools: a call now has a contract

The largest internal change, and the one most visible to plugin authors. A tool returns a
ToolResult, not a string. A permission verdict is a pure function that comes with a reason,
and a refusal speaks in terms of what was denied rather than describing the host's plumbing. Eight
concerns that used to be wired in by hand became a pipeline; the outcome of a call reaches observers
and is covered by tests. A tool set is levelled by the user and raised by the chat. An exposure
profile
decides what an outside caller is allowed to see — which is what made MCP possible:
SPLA tools are now served over stdio end to end, so an external agent can use them.

The LLM path is a pipeline

ILLMService was replaced by a middleware pipeline behind a single gateway, with each stage named
and diagrammed. Providers became projects dispatched by provider, which is how LocalAI, OpenRouter
and LM Studio now coexist without special cases.

A loop guard catches degenerate, repeating generation in the output stage instead of letting it
run until the context ends. The reasoning lever is driven by what the provider actually
advertises rather than an assumed standard — there isn't one, and three providers disagreed about it
in measurable ways. OpenRouter context windows feed the status bar's occupancy pill, and the panel
says why a figure is missing instead of showing nothing.

Plugins

SSH gained live pty sessions with streaming output, SFTP transfer staged through .tar
containers, upload as the true mirror of download, and a terminal that follows the window instead of
the size its pty was born with. Roslyn builds, runs and tests .NET projects as tools. OneC
got a Vue configuration browser; its dead Avalonia layer was removed. Browser landed the first
wave of Playwright automation with a screencast panel.

All plugin panels moved from Avalonia to the web client, so a plugin ships one UI, not two.

Server, CLI and multi-user

Domain identity over NTLM, per-user file areas, group sharing, and a pluggable identity provider.
Projects can be created by name into the calling user's own area, and token/Origin authentication
gaps in the service were closed. The CLI moved to Spectre.Console.Cli and gained a headless batch
runner, so it can be driven by another program rather than only by a person. spla chat run also
gained --sys-prompt-file, so a long system-prompt variant no longer has to be typed inline.

Build and release

This cycle is the first with continuous integration: every push to work and every pull request
into main builds the solution, runs the .NET tests, type-checks and bundles the web client, and
runs its vitest suite. Releases are automated — a push to main that touches source paths (or a
manual run against any ref) re-runs those checks against the exact commit being released, publishes
apps and plugins, and attaches SPLA.zip to a GitHub release, removing its own tag again if the
publish fails. There is no separate "now release it" step: main receives nothing but releases, so
the merge already is the decision. A tag-push trigger was considered and dropped — GitHub does not
document whether a paths filter applies to tag pushes, and a release pipeline should not rest on
that being guessed right.

Alongside that, published builds stamp the branch they came from so an experimental build cannot be
mistaken for a working one, web dependencies install when the manifests change rather than once per
checkout, and a publish no longer fails just because git is missing.

Structure and documentation

Projects were reorganized into a layered src/ tree, SPLA.Runtime was extracted so a headless
worker can reference the runtime without the CLI, service or UI, and docs/ was split by lifetime
into ADR (why), PLAN (how) and IDEA (maybe). Three demo workers show the boundaries hold —
VisionAgent, LogSentry and Summarizer — plus a RemoteWeb project demonstrating browser
automation over the LAN.

Breaking changes

  • A tool result is a ToolResult, not a string. Plugins returning strings must be updated.
  • A project's root is its manifest's own directory, and nothing can move it. Use mounts to reach
    outside.
  • .spla/skills is gone. Skills come from declared sources.
  • .spla is not readable through the sandbox the way it used to be.

Changes

Added

  • Continuous integration: solution build, .NET tests, web type-check, bundle and vitest, on every
    push to work and every pull request into main.
  • Release automation: merging into main re-runs the checks, publishes apps and plugins, and
    attaches SPLA.zip to a GitHub release; a manual run does the same against any ref.
  • MCP: SPLA tools served over stdio, usable by an external agent.
  • Mounts: folders outside the project root, declared by name, each its own security zone.
  • Multi-project service: several projects at once, with a project picker in the client.
  • Server deployment: domain identity over NTLM, per-user file areas, group sharing.
  • DPAPI secret store with explicit scopes and per-entry ACLs.
  • Skill library as a project of its own, fed by declared sources, with a librarian that answers by
    subject and one that reads the question.
  • SSH: live pty sessions, SFTP transfer, upload as the mirror of download.
  • Roslyn plugin: build, run and test .NET projects as tools.
  • Browser plugin: first wave of Playwright automation with a screencast panel.
  • OneC: Vue configuration browser.
  • Headless batch runner in the CLI, now on Spectre.Console.Cli.
  • --sys-prompt-file on spla chat run, reading a system-prompt addition from a file the way
    --prompt-file already does for prompts.
  • Loop guard against degenerate LLM generation.
  • Reasoning lever driven by what the provider advertises.
  • Branch stamp on ...
Read more

v0.1.2

Choose a tag to compare

@KOE73 KOE73 released this 19 Jun 18:31

SPLA v0.1.2

Major interim release of the agent architecture. This version adds the first complete layer for agent orchestration, skill sessions, project/session memory, checkpoints, marks, clarification flow, and spawned agents.

Highlights

  • Added new SPLA.Agent project with conversation orchestration, system prompt building, tool mode filtering, and spawned agent support.
  • Replaced the old tool.help flow with agent.info as the unified entry point for tools, skills, and capabilities.
  • Added dedicated memory tools: agent.memory.get/set/list/delete/clear.
  • Added skill lifecycle tools: skill.activate, skill.deactivate, skill session state, and skill file watching.
  • Added context tools for checkpoints, marks, rollback, and restore.
  • Added agent.clarify for structured clarification requests.
  • Extended permission and scope models for agent, session, and project-level behavior.
  • Improved LM Studio integration with model management, tool schema serialization, and better tool call support.
  • Reworked network skills into SPLA.Skills.Network, added network-range-audit-loop, and expanded host inventory KV guidance.
  • Updated Avalonia UI with a new chat view layer, session view model, clarification view, context/KV debug windows, and delete confirmation.
  • Added tests for memory tools, skill sessions, agent spawning, active skills, tool naming, progress scopes, and context assembly.
  • Updated build version to 0.1.2.

Documentation

  • Added documentation for skills, system prompt rules, tool arguments, and data ownership.
  • Updated security, plugin, structure, and tool-help documentation.
  • Added plans for skill lifecycle and system prompt rules.

Verification

git diff --check is clean. Full build verification could not be completed in the current environment because files in obj/bin were locked (Access denied while writing .pdb files and copying network skills into SPLA.CLI\bin). No separate compiler error was confirmed.

v0.1.1: refactor: consolidate chat UI views and add sidebar/message ViewModels

Choose a tag to compare

@KOE73 KOE73 released this 14 Jun 17:50

SPLA v0.1.1

Chat UI overhaul and Network plugin skills.

Changed

  • Chat rendering — unified view replacing the previous Bubble / Classic / Diagnostic stream views; WebView renderer extended with Markdown and Mermaid diagram support
  • Message ViewModels — split into typed classes (User, Assistant, System) instead of a single generic ViewModel
  • Sidebar — new SidebarPanelView with its own ViewModel and node hierarchy
  • Settings — ChatDisplayProfile type added; SettingsResolver and SplaSections extended to cover display profiles
  • Density themes — all four density files (Nano / Mini / Norm / Max) updated for the new layout

Added

  • Network plugin skills — five agent skill definitions shipped with the Network plugin:
    • dns-diagnostics — DNS resolution and propagation checks
    • host-audit — per-host reachability and port survey
    • lan-discovery — local network device discovery via ARP
    • smtp-probe — mail server connectivity and banner checks
    • ssl-audit — TLS certificate inspection

First

Choose a tag to compare

@KOE73 KOE73 released this 11 Jun 13:02

SPLA Initial Release

First published SPLA snapshot.

Included

  • Avalonia desktop UI
  • CLI entry point
  • SPLA project file support
  • Agent documentation and permission model docs
  • Plugin host infrastructure
  • MCP core and basic tools
  • OneC plugin foundation
  • Network plugin foundation
  • Observability project
  • Centralized common .NET project settings via Directory.Build.props

Notes

This release is the initial GitHub baseline. Previous development history was squashed into a single root commit.