php-serena/8.5-trixie adds Serena v2 REPL, PHPactor and JavaScript/TypeScript tooling to xorder's PHP 8.5
development image. It is an independent stdio MCP service for source discovery
and editing. The catalog is the availability authority:
the authored image is not available until publication and verification produce
an accepted release record. No image is pulled automatically during MCP startup.
The prepared source remains Serena commit b79e2a55f9d4072084977dd35bd07d31146d88b9.
The dependency-only security patch and
effective uv lock pin AnyIO 4.14.2,
PyJWT 2.14.0, certifi 2026.10.23, Pillow 13.0.0, filelock 4.2.1 and Werkzeug
3.1.9. The latter two address the November 2026 Dependabot alerts; the other
fixes were identified by the publication scan. Certifi follows the
upstream recommendation
to use 2026.10.19 or later; Pillow 13 fixes the five critical image-decoder
findings in the scanned 12.3.0 dependency. The separate Mago/Serena lock also
includes filelock 4.2.1 and Werkzeug 3.1.9 through its own dependency-only patch.
The build checks the
original upstream lock hash before applying the patch, then installs the effective
closure with uv sync --locked. Inventories identify the upstream and effective
lock hashes separately. Source edits, lock changes, and installed dependency
versions must pass the normal image behavior and publication assurance gates.
The offline acceptance fixture measures these six installed packages, loads
certifi's CA store and encodes/decodes a PNG with Pillow before exercising the
existing Serena/PHPactor and JavaScript navigation contracts.
Select an available image/php-serena/8.5-trixie entry from the catalog, pull its
exact digest, and retain it in the MCP client's configuration. Configure the
client to launch this command, supplying absolute paths and the selected digest:
python3 /path/to/xorder/examples/serena/run.py /path/to/uxor \
--project . --image "$SERENA_IMAGE"Use one project selection per worktree. For uxor, use --project . to
activate the checkout root and include original recipes, controllers and demo
source. Paths below are relative to that root. --project demo remains useful
for demo-only PHP inspection, with paths relative to demo, but switching
between . and demo creates separate index caches and pays for two cold indexes.
The runner mounts the whole checkout at /workspace in either case.
Install dependencies from the consuming application's own Composer lock with its
normal development runner before using Serena. This image does not supply a
substitute application vendor/. Existing uxor app/browser images and
their launch configuration remain useful independently.
The image defaults to the persistent serena_repl interface. Call
initial_instructions first, then pass its issued session ID as session on every
serena_repl call, with Python in code. For example, within one Serena session:
s.info('lsp.find_symbol', 'lsp.find_referencing_symbols')
s.lsp.find_symbol('CspNonce', relative_path='demo/src/Security/CspNonce.php')
s.lsp.find_referencing_symbols('CspNonce', 'demo/src/Security/CspNonce.php')Use upstream API discovery for the selected revision. The REPL retains variables between cells. A failed cell may already have edited source: inspect its textual error and the resulting files before retrying. Reconnecting starts a new REPL; variables and temporary memories are lost, while source edits remain. Optional matching indexes survive. There is no automatic replay of a failed or interrupted cell.
These additions require the new 1.1 image after publication and acceptance; an older digest does not gain new binaries or launcher options. Shell access uses the same MCP service and needs no harness MCP registration:
python3 examples/serena/client.py query find_symbol LabController \
--workspace /path/to/uxor --project . --image "$SERENA_IMAGE" \
--path demo/src/Controller/LabController.php --cache-dir /path/to/serena-cacheFor repeated work, launch one daemon per worktree. Its socket directory must be owned by the current user with mode 0700. Calls are serialized against one REPL; errors return JSON and exit nonzero. Nothing automatically replays a failed edit.
mkdir -p /path/to/private-serena
chmod 700 /path/to/private-serena
python3 examples/serena/client.py serve --workspace /path/to/uxor \
--project . --image "$SERENA_IMAGE" --write \
--languages php_phpactor,typescript --request-timeout 180 \
--cache-dir /path/to/serena-cache --socket /path/to/private-serena/session.sock
# From another shell:
python3 examples/serena/client.py call --socket /path/to/private-serena/session.sock \
--code "s.edit.replace_content('demo/src/Example.php', 'old', 'new', 'literal')"
python3 examples/serena/client.py status --socket /path/to/private-serena/session.sock
python3 examples/serena/client.py stop --socket /path/to/private-serena/session.sock--write enables edits and a writable source mount. --read-only is available for inspection. The MCP initial_instructions response also exposes structuredContent.session_id. Request timeouts are configurable independently of the shell startup timeout; a stopped language server reports recovery through s.lsp.restart_language_server() or a session restart.
End a call --code cell with the expression whose value you want returned.
The current REPL returns the last expression, so a cell ending in print(value)
can return None; use value as the last expression instead. The shell client
passes through the MCP result and does not claim separate captured stdout.
For more than one query, use the daemon above: one-shot queries start and stop a
language server each time, and its shutdown can report a termination timeout
before the process is killed. The daemon avoids that cost between calls.
| Source | Navigation | Editing |
|---|---|---|
| PHP | PHPactor symbols and references | Serena source/symbol editing in write mode |
| JavaScript / TypeScript | TypeScript language server symbols and references | Serena source/symbol editing in write mode |
| Twig / YAML service IDs | Text search; semantic coverage is not established | Text edits in write mode |
| Stimulus actions/lifecycle and PHP attribute-routed entry points | Text search for convention-based invocation; semantic references only cover explicit code references | Text or source edits in write mode |
Stimulus default-exported classes are named default. Qualify the member and
supply its original source file to disambiguate controllers:
s.lsp.find_symbol('default/connect', relative_path='modal/assets/controllers/flowbite_modal_controller.js')An empty references result does not prove that a Stimulus method or routed PHP
controller is unused. Inspect data-action, lifecycle method names and route
attributes with text search; these entry points are invoked by convention.
Navigation honors project ignore rules. Use --project . to work on the kit's
original recipes outside demo; generated demo controller copies may be
gitignored. JavaScript reference queries include eligible workspace sources even
when the application has no jsconfig.json or tsconfig.json, without writing
either configuration file into the checkout.
The Linux/amd64 runner requires Python 3.9+ and a working Docker engine with the
chosen image already present. Each invocation creates a separate container and temporary REPL state. Optional index storage is scoped to the canonical checkout, project and exact image, preserving worktree separation. It runs as the
host UID/GID, keeps protocol stdout clean, disables runtime networking, and
exposes only the selected checkout. It mounts no host home or Docker socket.
The checkout is read-only by default, enforced by the mount as well as upstream
editing APIs. Pass --write explicitly to allow the REPL and PHP tooling to modify
a trusted checkout. --read-only explicitly selects the default behavior.
Startup completes PHPactor's initial project index before exposing MCP. Cold
startup therefore takes longer for large dependency trees, but the first reference
query sees a complete initial index. Indexing uses the private session cache by default. Pass --cache-dir /absolute/cache/path to persist it. A complete-index marker binds source bytes (including installed PHP dependencies and sibling kit source), settings and PHPactor bytes. Changed inputs complete an incremental build before serving; unchanged inputs reuse the completed index. One process holds a cache lease for its lifetime; reuse the daemon for concurrent clients. Startup needs no runtime networking and writes no generated configuration into the checkout.
Serena's Python REPL has the container user's capabilities. This runner does not implement Agentscient's role policy, operation locks, process auditing or work coordination. Give concurrent editing sessions separate worktrees, or coordinate their writes through the owning application.
The launcher reads existing .serena/project.yml and project.local.yml, applies
the prepared PHPactor default when no backend is selected, and keeps generated
configuration outside the source tree. Repository activation commands and
language-server-specific settings are discarded; global trusted project paths are
explicitly empty. A phpactor_version or ls_path override is rejected with an
actionable error, as is an incompatible backend selection. This profile keeps newly written Serena memories session-local. PHPactor automatic configuration prompts are disabled through its launch configuration and initialization options, including on a clean read-only checkout.
The image provides PHP semantic tools, a PHP runtime and Composer. Acceptance
uses actual uxor Symfony source: class/method lookup, cross-file references,
an edit and semantic reread, persistent REPL variables, a partial edit followed by
an error, and a fresh read-only session. PHP attributes and constructor types are
present in this consumer. JavaScript/TypeScript uses the prepared TypeScript language server (--languages php_phpactor,typescript). This does not establish semantic Twig navigation,
resolution of service identifiers from YAML, or runtime container inspection.
Use the application's installed Symfony/Mate capabilities for runtime facts.
Dependency installation happens before acceptance starts the network-disabled MCP runner. The test establishes offline language-server startup and operations; it does not claim that an arbitrary application's dependencies are already cached.
The parent is the exact PHP 8.5/Trixie artifact selected by xorder's normal build and publication machinery. Existing accepted parents are reused. To build a candidate with an explicitly chosen accepted parent:
python3 scripts/build.py php-serena/8.5-trixie image-library-serena:candidate \
--parent "$PHP_DEV_DIGEST" --inventory out/php-serena.jsonThe shared verifier checks inherited PHP capabilities and runs
tests/fixtures/serena/check.py against its pinned uxor revision. The
fixture clones a disposable checkout, installs its Composer lock without scripts
or plugins, and drives the public runner through real stdio MCP. No model account
is required. Evidence is written to out/serena/acceptance.json; CI retains it
alongside image inventory and metrics. Publication repeats behavior checks before
catalog availability. A passing PR test is not a published artifact.
Serena source and its upstream uv.lock are pinned to
b79e2a55f9d4072084977dd35bd07d31146d88b9 (v2 beta). The Dockerfile pins uv and
PHPactor; requirements-build.txt contains the hash-checked build-tool closure.
Installation uses uv sync --locked --no-build-isolation and checks that upstream
metadata remains unchanged. Source and upstream licenses remain in
/opt/serena-source. The inherited PHP image owns its OS package provenance;
this Trixie variant does not claim Agentscient's Bookworm snapshot configuration
or byte-identical rebuilds.
Update source/backend pins together when needed, regenerate the build-tool closure against that source's lock, allocate a new image revision, and repeat real MCP acceptance. A source-label check alone cannot prove that packaging changes landed; select by the verified image digest and measured inventory.
This package applies the existing Agentscient work, inspected on dev on
2026-10-10, to a standalone xorder distribution:
- PR 304: selected v2 beta REPL, persistent state, real PHP discovery/editing, partial failures and restart.
- PR 316: separate container provider, prepared checksum-pinned PHPactor, offline execution and workspace binding. It superseded the initial Intelephense packaging for this route.
- PR 373: upstream runtime lock plus a separately locked build-tool closure, exact source and artifact checks.
- PR 380: observe-only process auditing and its limits. That Agentscient-owned observer is not included here.
The prior Serena readiness and session-handoff research supplied acceptance cases; current source supplied implementation facts. Agentscient's coordination policies are not imposed on independent projects. Upstream remains oraios/serena.