name: tritonkit-real-project-regression description: Use when TritonKit moves from demo/self-test into a real iOS app, Harmony app, or customer project for regression testing, adoption validation, or actual requirement discovery. Guides the AI agent to isolate external repo changes, run release CLI plus host-side or embedded runtime checks, collect machine-readable evidence, and turn real-project gaps into docs, fixes, or GitHub issues. metadata: version: 0.1.0-dev
TritonKit Real Project Regression
Principle
Real-project validation is not the same as demo smoke. Treat the business app as an external system under test: avoid mixing its local changes into TritonKit commits, collect reproducible evidence, and keep every finding traceable to a command, output file, screenshot, or issue.
Workflow
- Confirm the real app, target branch, device/simulator, and the requirement being validated.
- Check both repos before changing anything:
- TritonKit:
git status --short --branch - real app repo:
git status --short --branch
- TritonKit:
- Prepare the macOS
tritonCLI:- Prefer the released Homebrew binary when validating an external app:
brew install NeptuneKit/tap/tritonorbrew upgrade triton. - If testing unreleased TritonKit changes from this repo, keep using the local release CLI.
- If copying the local build into an existing
PATHlocation whiletriton servemay be running from that path, stop the server first or replace through a temporary file and same-directorymv. - Confirm the active binary with
triton version --jsonor.build/cli/release/triton version --json.
- Prefer the released Homebrew binary when validating an external app:
- Integrate TritonKit into the app only through the intended DEBUG-only package path when embedded runtime access is required:
- If the task only needs Harmony host-side emulator discovery, readiness, app inspect, or app launch, do not add an app dependency; use the Harmony host-side commands below.
- If the task needs iOS embedded runtime access, use the iOS package path below.
- If the task needs Harmony embedded runtime access, use the Harmony package/source path below and keep provider semantics opt-in.
- SwiftPM or CocoaPods as requested; CocoaPods examples must use
:configurations => ['Debug']. - For SwiftPM, distinguish build settings from product dependencies: TritonKit uses the package
TRITONKIT_RUNTIME_ENABLEDDebug compile flag, but SwiftPM still does not provide CocoaPods-style configuration-scoped product dependencies. Keep source-level#if DEBUGisolation, or create a separate Debug-only app target/scheme if Release must not link TritonKit at all. - Put all app-side TritonKit code in a dedicated iOS file such as
TritonKitDebugBootstrap.swift. - Wrap the entire file in
#if DEBUG, includingimport TritonKitandTritonKit.shared.start(...). - Call the bootstrap only from a
#if DEBUGbranch in AppDelegate, SceneDelegate, or SwiftUIonAppear. - Prefer
TritonKit.shared.start()or thestart { config in ... }facade; only use lower-leveldelegate/connect(host:port:)when the real app needs a custom delegate.
- Start server with explicit port:
triton serve --host 127.0.0.1 --port 19421. - Verify connection and target identity:
triton doctor --jsontriton status --jsontriton capabilities --json- before using
baguette, rawxcrun/simctl,hdc,adb, DevEco Emulator CLI, XcodeBuildMCP, or rawxcodebuild, preserve Triton-first fallback gate evidence fromstatus,doctor,capabilities,schema, orplan; fallback is allowed only after Triton reports failure, unsupported capability/scope, or missing schema/capability for the required local emulator action; - use
doctor.checks[]first for ordered recovery, and preservedoctor.nextWorkflowsplus each check'sworkflowCategoriesso the regression report keeps the affected workflow taxonomy without re-deriving it from capabilities; triton list --json- use
capabilities[].group,requiredBy,nextAction, andevidenceto decide whether the next step is target selection, runtime connection, Xcode preparation, action execution, assertion, or evidence capture; if a schema-provided capability lacks those planning fields, treat that as a TritonKit contract bug before relying on it; - treat duplicate capability names in schema or capabilities output as TritonKit indexing bugs before deriving a reusable regression plan;
- treat empty or duplicate
requiredBy/evidenceentries as TritonKit metadata bugs; reusable regressions need clean workflow and artifact categories; - for iOS
AVPlayer/AVPlayerViewControllerflows, runtriton snapshot --include media,ax,screenshot-metadata --jsonbefore asserting playback; preservemedia.surfaces[],media.controls[],automationConfidence,fallbackAdvice[], andevidenceCommands[]; - if media
automationConfidenceissurface-only, treat rendered video as observation evidence only; require app-owned DEBUG overlay controls with stable accessibility identifiers before claiming pause, resume, seek, elapsed, duration, progress, or route-release control assertions; - for app-domain readiness that cannot be proven from generic UI, inspect
triton runtime manifest --jsonsemanticDomains[]first, then runtriton snapshot --include semantic,app,scene --json; preservesemantic.domains[], providersource,confidence,state,schema,actions,redaction, andevidenceCommands[]; - treat
app-semantic-stateas provider-backed business state andapp-semantic-actionas provider action-catalog discoverability. Do not build reusable regressions around generic provider action execution until a dedicated command contract exists; - treat unknown
capabilities[].groupvalues as TritonKit taxonomy bugs; reusable regressions should only depend on the fixed groupsaction,assert,bootstrap,evidence,host,observe,semantic,replay,route,runtime,smoke,target,webview, andxcode; - treat unknown
capabilities[].requiredByvalues as TritonKit workflow taxonomy bugs; reusable regressions should only depend onaction,app,assert,evidence,observe,project,replay,route,runtime,smoke,target,webview-check, andxcode; - treat unknown
capabilities[].evidencevalues as TritonKit artifact taxonomy bugs; reusable regressions should rely on real stdout JSON, schema/status output, host artifacts, runtime snapshots, WebView provider output, route assertions, input results, evidence bundles, smoke summaries, tritonplans, Xcode artifacts, or unsupported envelopes; - treat empty
capabilities[].evidencearrays as TritonKit contract bugs before building a reusable regression; every capability needs at least one machine-readable proof source; - verify
capabilities[].nextActionagainst schema before turning it into a reusable script; platform-specific app install flags must match the target, for example iOS--app <path.app>versus Harmony--hap <path.hap>; - treat
nextAction.requiresLongRunningProcess=trueas valid only for real long-running process commands such as server bootstrap, JSONL build, or host proxy serve; when present, verifyreadyEvents,finalEvents, andterminationSignalsbefore daemonizing it, and never daemonize ordinary target, observe, action, assertion, or evidence commands; - treat malformed
nextAction.argsplaceholders as TritonKit contract bugs; reusable regressions should receive placeholders as standalone argv tokens, not string fragments that require custom parsing; - treat malformed placeholders in schema next commands, schema examples, or plan step commands as TritonKit contract bugs; reusable regressions should not depend on shell redirection or partial placeholder strings;
- treat blank or duplicate command-level/subcommand-level
nextCommands[]entries as TritonKit recovery list quality bugs before copying recovery suggestions into reusable regression scripts; - treat schema
nextCommands[]root commands outside the recovery command taxonomy as TritonKit contract bugs; reusable regressions should only copy recovery suggestions whose root command has a defined diagnostic, discovery, target, project/Xcode, observe, action, assert, evidence, replay, or smoke role; - treat recovery roots without a stable category as TritonKit taxonomy bugs; reusable regressions should know whether a suggestion is
diagnose,discover,prepare-target,project,observe,act,verify,archive,replay,smoke, orplan; - prefer schema
recoveryCommands[]when constructing reusable recovery branches; it must mirrornextCommands[]and expose one{command, category}entry for each recovery suggestion; - treat
failureCodes[]that cannot be mapped to valid recovery category families as TritonKit taxonomy bugs; reusable real-project flows should be able to classifyerror.codebefore choosing concrete recovery commands; - treat artifact/output failure codes without an
archiverecovery category as TritonKit recovery coverage bugs; real-project regressions need evidence/capture/export-style next steps when output paths are rejected, writes fail, or artifacts are too large; - treat assertion/route/text-not-found failure codes without a
verifyrecovery category as TritonKit recovery coverage bugs; reusable regressions should have wait/assert/route-style next steps when expected UI or navigation state is not met; - treat runtime transport failure codes without a
diagnoserecovery category as TritonKit recovery coverage bugs; reusable regressions need status/doctor/capabilities-style next steps when server, runtime, or request transport fails; - treat target failure codes without a
prepare-targetrecovery category as TritonKit recovery coverage bugs; reusable regressions need target/device/sim/app-style next steps, preferablytriton target resolve <selector> --json, when a selector is ambiguous, missing, offline, not ready, or unavailable; - treat Project / Xcode failure codes without a
projectrecovery category as TritonKit recovery coverage bugs; reusable regressions need Xcode discovery/defaults next steps, preferablytriton xcode discover --path . --json, when workspace, scheme, or Xcode idle state is missing, ambiguous, invalid, or unavailable; - treat action/step failure codes without an
actrecovery category as TritonKit recovery coverage bugs; reusable regressions need executable action next steps, preferablytriton input --json --summary --strict, when an action batch or replay step fails; - treat destructive/confirmation failure codes without a
planrecovery category as TritonKit recovery coverage bugs; reusable regressions need planning or policy-review next steps, preferablytriton plan --format json, when a host-side destructive command requires confirmation or policy; - treat unsupported failure codes without a
planrecovery category as TritonKit recovery coverage bugs; reusable regressions need capability-boundary planning next steps, preferablytriton plan --format json, when a runtime, WebView, provider, or action capability is unavailable or method-blocked; - treat missing or mismatched
capabilities[].nextAction.categoryas TritonKit capability contract bugs; reusable regressions should know each capability's next-step stage without parsing command roots by hand; - treat missing
doctor.checks[].nextAction.categoryin the doctor output contract as a TritonKit diagnostic contract bug; reusable regressions should get the same stage vocabulary from doctor, capabilities, and plan; - treat missing or invalid
doctor.checks[].workflowCategoriesas TritonKit diagnostic planning bugs; reusable regressions should be able to see which workflow taxonomy each doctor check blocks before consulting the full capabilities matrix; - treat missing or invalid
doctor.nextWorkflowsas TritonKit diagnostic planning bugs; reusable regressions should be able to identify the first actionable blocked workflow directly from the doctor root; - treat missing or invalid
plan.nextWorkflowsas TritonKit planning routing bugs; reusable regressions should be able to see whether the recommended lane issmoke,app,route,assert,evidence, ortargetbefore parsing individual step commands; - treat missing or invalid
plan.steps[].workflowCategoriesas TritonKit planning routing bugs; reusable regressions should be able to enter a concrete step and still know which workflow taxonomy it belongs to, without rebuilding that mapping from command strings; - treat missing or invalid replay inspect / dry-run
steps[].workflowCategoriesas TritonKit replay routing bugs; reusable regressions should be able to compare offline inspect and dry-run against the same workflow lane vocabulary before touching the app; - treat missing
error.nextAction.categoryinTKCLIErrorDetail?output contracts or failure shapes as TritonKit error-envelope contract bugs; reusable regressions should route failures by category without parsing human-readable hints; - treat shell control operators in
plan.steps[].commandas TritonKit plan bugs; reusable regressions should receive single Triton invocations as the human-readable/logging form and express stdin/file prerequisites through metadata or the surrounding plan; - prefer
plan.steps[].argvover parsingplan.steps[].command; if argv is missing or empty, report a TritonKit plan execution contract bug before building reusable runners; - treat missing or mismatched
plan.modeas TritonKit plan contract bugs; reusable regressions should know whether a plan is bootstrap recovery or goal-specific workflow planning before selecting runners; - treat missing or mismatched bootstrap response
surfacefields as TritonKit contract bugs; reusable regressions should be able to distinguish status facts, ordered diagnostics, capability matrices, and plan responses from JSON alone; - treat missing or mismatched
plan.steps[].categoryas TritonKit plan bugs; reusable regressions should know each step's workflow stage without parsing command roots by hand; - treat missing
plan.steps[].requires,plan.steps[].expectedArtifacts, orplan.steps[].stopConditionsas TritonKit plan bugs; reusable regressions should know prerequisites, evidence, and stop gates before executing a real app flow; - treat missing
steps[].argv,steps[].category,steps[].requires,steps[].expectedArtifacts,steps[].stopConditions, orsteps[].validationErrorsfromtriton plan inspect <file.tritonplan> --jsonas replay-plan inspect bugs; reusable regressions should be auditable offline beforereplay --dry-runor execution; - treat missing
steps[].argv,steps[].category,steps[].requires,steps[].expectedArtifacts, orsteps[].stopConditionsfromtriton replay <file.tritonplan> --dry-run --jsonas replay result bugs; reusable regressions should compare dry-runsteps[].argvand step metadata against inspect metadata before touching the app; - treat replay dry-run accepting statically invalid steps as TritonKit validation bugs; reusable plans should fail before touching the app when
taphas multiple selectors,waithas multiple conditions,paste/typelacks text, orwaitlacks a condition; - before building reusable parsers or regression assertions from schema output, check that relevant
outputContracts[]entries have non-emptyselector,model, and field definitions with fieldname,type, anddescription; missing details are TritonKit contract bugs, not app integration issues; - treat duplicate
outputContracts[].selectorvalues within the same command as TritonKit schema lookup bugs before deriving reusable parsers or assertions; - treat any
subcommands[].outputSelectors[]value that is absent from the parent command'soutputContracts[].selectorset as a TritonKit schema lookup bug before deriving reusable parsers or assertions; - if a schema command advertises a failure shape or non-zero failure exit but has empty
failureCodes[], report a TritonKit schema bug before relying on it for automated recovery; - if
failureCodes[]contains non-lower_snake_case values or duplicates, report a TritonKit schema recovery bug before mappingerror.codeto reusable regression recovery logic; - if a subcommand exposes a failure code that is absent from the parent command schema, report a TritonKit schema consistency bug; reusable regressions should not need to merge undocumented parent and child code sets by hand;
- if options or subcommands have empty names, empty option types/descriptions, empty subcommand summaries, or duplicate names in the same parent command, report a TritonKit schema quality bug before turning the schema into reusable automation;
- if command names, subcommand names, or pure long flag aliases are not stable lower-kebab CLI keys, report a TritonKit schema routing bug;
- if Subcommand / Task usage synopsis appears in
options[]instead ofusageForms[], report a TritonKit schema-shape bug before deriving an option parser from it; - if positional arguments appear in
options[]instead ofargumentForms[], report a TritonKit schema-shape bug before deriving argv or flag validation from it; - if
subcommands[].requiredOptions[],optionalOptions[], oroneOfRequiredOptions[]references a flag or positional argument absent from the parent command'soptions[]orargumentForms[], report a TritonKit schema reference bug before building a reusable regression; - if a command with
subcommands[]also has non-empty command-levelrequiredOptions[], report a TritonKit schema-shape bug; reusable regressions should read subcommand requirements from the subcommand itself, not from parent-level prose summaries; - if
defaultProviders[]orinheritsDefaultsFrom[]contains something other than a schema-backedtriton ...command, report a TritonKit planning contract bug before relying on that default source; - if command-level or subcommand-level
artifacts[]contains unknown or duplicate values, report a TritonKit artifact taxonomy bug before relying on those artifacts in a regression report; - if
jsonlEvents[]contains malformed or duplicate event keys, orfinalEventKindis missing from the samejsonlEvents[], report a TritonKit JSONL event contract bug before building long-running command monitors; - if a schema object is
retryable=truebut has emptynextCommands[], report a TritonKit recovery contract bug before making it part of a reusable real-project flow; - if a command or subcommand exposes
failureCodes[]but neither that object nor its parent command provides a usablenextCommands[]recovery path, report a TritonKit recovery contract bug before relying on it for automated regression recovery; - if schema examples use commands or flags that schema does not declare, report a TritonKit schema/example contract bug instead of copying the example into a real project regression script;
- treat
plan-inspectas offline.tritonplansummary inspection andreplay-dry-runas offline validation only; real replay, smoke, wait, assert, and evidence capture remain separate proof steps. - for iOS Simulator embedded runtime, confirm
triton list --jsonexposestriton:ios-simulator:<SIMULATOR_UDID>andsimulatorUDID; - if multiple iOS Simulator runtime targets are connected, pass
--target <SIMULATOR_UDID>or--target triton:ios-simulator:<SIMULATOR_UDID>for runtime commands; defaulttriton:localshould returnambiguous_target. triton runtime manifest --jsontriton state app --jsontriton state scene --jsontriton state route --jsontriton state responder --jsontriton snapshot --include app,scene,route,ax,geometry --jsontriton ledger --limit 50 --jsonl- when the real app has hybrid pages, verify WebView state explicitly:
triton webview list --platform ios --jsontriton webview current --platform ios --jsontriton webview current-url --platform ios --jsontriton route assert-current-url '<expected-url>' --platform ios --jsontriton webview call <method> --platform ios --jsononly for page/app allowlisted methods;triton webview events --platform ios --limit 50 --json;- read
webview list/current.primarySourcefirst; provider-backed results usewebview-provider, while runtime AX and host layout candidate discovery useruntime-treeorhost-layout; - treat iOS
webview list/currentas candidate discovery unlessprimarySource.name=webview-providerand provider metadata includes URL/session details; - treat
webview current-url,webview snapshot,webview call,webview events,webview wait, androute assert-current-urlas provider-level evidence, not generic AX/layout proof; - treat Harmony host layout Web candidates as host-only until an embedded WebView provider is registered.
- Prepare host-side simulator state through Triton before falling back to raw
xcrun:- list simulators:
triton sim list --json; - for repeated multi-simulator work, create a stable selector:
triton device alias set iphone15 --platform ios --target <udid> --json; - prefer unified selectors for common host actions:
--device <alias-or-id>; use--simulator <udid-or-booted>only when an iOS-specific selector is clearer; - set a workspace default simulator when a flow will be reused:
triton sim use <udid> --json; - boot and wait for readiness:
triton sim boot <udid> --wait --jsonl; - list installed apps:
triton app list --device iphone15 --user-only --json; - inspect installed app metadata:
triton app info --device iphone15 --bundle-id <bundle-id> --json; - install simulator builds:
triton app install --device iphone15 --app <path.app> --json; - uninstall disposable simulator apps only with explicit policy:
triton app uninstall --device iphone15 --bundle-id <bundle-id> --confirm --json; - launch apps:
triton app launch --device iphone15 --bundle-id <bundle-id> --json; - terminate apps:
triton app terminate --device iphone15 --bundle-id <bundle-id> --json; - submit app debug routes:
triton app open-url '<url>' --device iphone15 --json; when a DEBUG embedded runtime is connected, prefertriton app open-url '<url>' --device iphone15 --wait-ready --snapshot --jsonto capture readiness and snapshot summary in the same result; - locate containers:
triton app container --device iphone15 --bundle-id <bundle-id> --kind data --json; - verify App preferences:
triton app prefs get <key> --device iphone15 --bundle-id <bundle-id> --json; - set simulator App preferences from property-list compatible JSON values:
triton app prefs set <key> <json-value> --device iphone15 --bundle-id <bundle-id> --json; - seed Swift
UserDefaults.data(forKey:)values explicitly with plist Data:triton app prefs set <key> --type data --base64 <base64> --device iphone15 --bundle-id <bundle-id> --jsonor--type data --hex <hex>; - capture host-side framebuffer:
triton sim screenshot --simulator <udid-or-booted> --output /tmp/<case>-sim.png --json; - only use raw
xcrun simctlwhen the needed capability is not intriton schema --command sim --jsonortriton schema --command app --json, and include that schema gap or Triton error envelope in the regression report.
- list simulators:
- Prepare Xcode build/test/run through Triton before falling back to XcodeBuildMCP or raw
xcodebuild:- discover project containers:
triton xcode discover --path <repo> --json; - set reusable defaults:
triton xcode use --workspace <workspace>|--project <project> --scheme <scheme> --configuration Debug --simulator <udid> --json; - list schemes:
triton xcode schemes --json; - diagnose current Xcode build/test occupancy before starting a smoke run:
triton xcode status --json; - wait for the current workspace to stop building/testing:
triton xcode wait-idle --workspace <workspace> --timeout <seconds> --json; - inspect app product settings:
triton xcode settings --jsonl --timeout <seconds>for large workspaces, ortriton xcode settings --jsonfor quick projects; - build:
triton xcode build --jsonl; - test:
triton xcode test --result-bundle /tmp/<case>.xcresult --jsonl; - build/install/launch:
triton xcode run --jsonl; xcode runonly proves build/install/launch submission; verify business readiness withtriton status,triton wait,triton assert, screenshot, or evidence.xcode settings/build/test/run --jsonlincludes stdout/stderr log paths and byte counts; inspect those artifacts before waiting longer or falling back.- use XcodeBuildMCP only as a temporary fallback when
triton schema --command xcode --jsonortriton xcode ... --jsonlevidence shows the needed capability is missing, unsupported, or failed with a stable error code.
- discover project containers:
- For HarmonyOS NEXT / DevEco Emulator validation, use Triton host-side device discovery before raw
hdc:- probe tools:
triton device doctor --platform harmony --json; - list HDC targets:
triton device list --platform harmony --json; - for repeated multi-emulator work, create a stable selector:
triton device alias set harmony-a --platform harmony --target <hdc-target> --json; - wait for boot readiness:
triton device wait-ready --device harmony-a --json; - close a Triton-supervised HVD with launchd cleanup:
triton device stop --platform harmony --hvd <hvd-name> --path <deployed-path> --confirm --json; - inspect app metadata:
triton app inspect --platform harmony --bundle <bundle> --target <hdc-target> --json; - install a debug HAP when needed:
triton app install --device harmony-a --hap <debug-signed.hap> --json; - launch an Ability:
triton app launch --device harmony-a --bundle <bundle> --ability <ability> --json; - run the one-command host smoke when available:
triton smoke harmony --device harmony-a --bundle <bundle> --ability <ability> --open-url <url> --wait-text <text> --screenshot /tmp/<case>.jpeg --evidence /tmp/<case>.tritonevidence --json; - when multiple targets are
Connected, pass--device <alias-or-id>or narrow with--platform,--name,--runtime,--state, and--ready;ambiguous_targetis the expected machine-readable failure. - if a disposable Harmony fixture app is needed, use the local
harmony-nextskill's minimal Empty Ability scaffold:- guide:
references/quickStart/ets/minimal-project-scaffold.md; - template:
references/templates/empty-ability-app/; - stable UI signals:
Harmony Smoke Ready,smoke-title,smoke-counter,smoke-increment; - validation path:
ohpm install,hvigorw --mode module -p module=entry@default assembleHap, HDC install/start,uitest dumpLayout, anduitest screenCap.
- guide:
- when validating a standalone Harmony embedded HTTP runtime before it is connected through
triton serve, use direct runtime checks:triton device runtime-url --device harmony-a --probe-manifest --jsonto prepare HDC fport and get thebaseURL; if you already have the raw HDC target id,--platform harmony --target <hdc-target>is the direct explicit form;- the Harmony demo host-access embedded runtime default is
http://127.0.0.1:28767;18765is reserved for the demo device-to-host gateway fallback path; triton runtime manifest --runtime-base-url http://127.0.0.1:<port> --json;triton state route --runtime-base-url http://127.0.0.1:<port> --json;triton snapshot --runtime-base-url http://127.0.0.1:<port> --json;triton ledger --runtime-base-url http://127.0.0.1:<port> --jsonl;triton set-text "密码" "$TRITON_PASSWORD" --secure --runtime-base-url http://127.0.0.1:<port> --jsonwhen an app action provider is registered.
- probe tools:
- Run observation before action:
- prefer one-shot regression capture when a full report is needed:
triton capture --case <case> --output /tmp/<case>.tritonevidence --json. - prefer one-shot evidence when a report or issue needs attachable proof:
triton evidence --name <case> --output /tmp/<case>.tritonevidence --json. - inspect an existing bundle without reconnecting runtime:
triton evidence inspect /tmp/<case>.tritonevidence --json. - summarize evidence before public handoff:
triton evidence summary /tmp/<case>.tritonevidence --json. - use
primaryArtifacts[]as the first inspection order; only fall back to fullartifacts[]when those high-signal entries are insufficient. - write a safe handoff bundle:
triton evidence redact /tmp/<case>.tritonevidence --profile ios-private --output /tmp/<case>-redacted.tritonevidence --json. triton geometry --jsontriton ax --jsontriton screenshot --json --output <path>triton export --format archive --output <path>
- Execute the smallest user-flow regression with machine-readable commands:
- when the next command sequence is not obvious, ask Triton for a task plan first:
triton plan ios-smoke --device <selector> --bundle-id <bundle-id> --url <url> --text <text> --evidence /tmp/<case>.tritonevidence --json,triton plan open-url --device <selector> --url <url> --text <text> --json,triton plan open-url --platform harmony --device <selector> --bundle <bundle> --ability <ability> --hap <path.hap> --url <url> --text <text> --evidence /tmp/<case>.tritonevidence --json, ortriton plan webview-check --expected-url <url> --text <text> --json; - if
triton plan open-url ... --jsonreturnsmode=bootstrap, executesteps[]to recover the environment, then continue withafterRecoverySteps[].argv; do not drop the original open-url verification workflow during server/runtime recovery; - treat task plans as command recommendations only; execute the returned steps explicitly and keep wait/assert/evidence as the pass/fail proof;
- treat any plan step whose
commandis prose instead of atriton ...command as a TritonKit plan contract bug; for a missing iOS runtime target, expecttriton xcode run --jsonor another schema-backed Triton command; - verify
plan.nextSteppoints to one returnedsteps[].id; if not, report a TritonKit plan contract bug before embedding the plan into a regression script; - if a plan returns a command whose root command, subcommand, or
--flagis not present intriton schema --json, treat that as a TritonKit schema/plan contract bug before using the command in a reusable regression; - if a schema subcommand
nextCommands[]entry references a root command, subcommand, or--flagabsent fromtriton schema --json, treat that as a TritonKit schema recovery contract bug before copying it into a reusable regression; - if command-level or subcommand-level
nextCommands[]contains shell pipes, redirection, command substitution, or multiple commands, treat it as a TritonKit recovery contract bug; reusable regressions should receive single Triton invocations; - if command-level
outputFormats[]contains unknown or duplicate values, treat it as a schema command taxonomy bug; valid values aretext,json,jsonl,logs,tree,auto,archive,file, andjson-metadata. - if a schema example contains zero or multiple
tritoninvocations, treat it as a schema/example contract bug before copying it into a real-project script; examples may useprintf, pipeline, or stdin preparation, but must expose exactly one reusable Triton invocation. - if an output contract field
typeis prose instead of a machine-readable scalar/DTO, optional, array, dictionary, or union type, treat it as a schema field contract bug before building parser logic around it. - if an output contract
modelis prose or raw Swift generic syntax instead of a machine-readable model, array, dictionary, or union type, treat it as a schema model contract bug before building parser logic around it. - if an output contract
selectoris not dot-separated lower-kebab, orkindis not single lower-kebab, treat it as a schema key contract bug before building parser logic around it. - if an
outputContracts[].formatvalue is notjson,jsonl, orarchive, treat it as a schema output taxonomy bug before building parser logic around it. - if an
outputContracts[].kindvalue is not documented by the schema tests and dev docs, treat it as a schema output taxonomy bug before building parser logic around it. - if the flow will be reused, first create or update a
.tritonplan; usetriton record --output <file.tritonplan> --jsononly as an editable starter template, not as proof that live recording happened; - inspect reusable flows with
triton plan inspect <file.tritonplan> --json, and readsteps[].argv/category/requires/expectedArtifacts/stopConditions/validationErrorsbefore dry-run; - dry-run reusable flows before touching the app:
triton replay <file.tritonplan> --dry-run --var key=value --var secret-env=ENV --json, and compare returnedsteps[].argv/category/requires/expectedArtifacts/stopConditionswith inspect output; - treat dry-run failure on ambiguous selectors or missing text/condition as a plan authoring issue; fix the
.tritonplanbefore running against the business app; - replay committed flows with
triton replay <file.tritonplan> --json, keeping secure values in environment variables and using--var <name>-env=<ENV>; - prefer action commands that are already machine-readable by default:
triton find "HTTP",triton tap "HTTP",triton type "hello",triton paste "console",triton clear; use--format textonly for human-readable debugging; - for form flows, prefer semantic embedded actions over a
tapplustypechain:triton focus "用户名" --json,triton set-text "用户名" "alice" --json,triton set-text "密码" "$TRITON_PASSWORD" --secure --json,triton select-segment "协议" "HTTP" --json,triton set-switch "记住我" on --json; - when labels repeat, run
triton find "<text>" --all; if a known point lies inside the intended candidate, prefertriton tap "<text>" --at x,y, otherwise choosetriton tap "<text>" --index <n>ortriton tap "<text>" --within x,y,width,height; - when
taporassertfails, read nearest candidates / nearestText and suggestedCommands from the JSON envelope before changing the test flow; - when
replayfails, read top-levelfailedStepIndex,failureCode,failureError,failureWorkflowCategories[],failureRecoveryCategories[],failurePrimaryArtifacts[],recoveryCommands[], andsuggestedCommands[]first; then inspect the failed steperrorpayload before broader step-by-step traversal or re-planning, includingwait/input/evidencefailures that only returnedok=false; iffailureError.nextActionexists, expect replay recovery commands to expose the same path; prefer failures that preserve runtime/target/transport codes over genericstep_failed; triton type --text <text>is the alternate flag form and must never be combined with positional<text>;triton press --button <button>is the alternate flag form; prefer positionaltriton press <button>;- for batch input, use
triton input --json --summary --strict; - when
tap,swipe,type, orpasteruns with--platform harmony, parse the host output contract selected by schema:host.harmony-tap,host.harmony-swipe, orhost.harmony-text-input; do not assume the result shape is the embedded runtimeinput.result. - when
waitruns with--platform harmony, parsehost.harmony-wait; do not assume the result shape is the embedded runtimewait.result. - when
axorscreenshotruns with--platform harmony, parsehost.harmony-artifact; do not assume the result shape is the generichost.artifactdevice-level contract. - when
pressruns with--platform harmony, parsehost.harmony-key-action; do not assume the selector remainshost.key-action. - when
clearruns with--platform harmony, expect a machine-readableunsupported_capabilityboundary; capabilities should exposeharmony-clear-textas unsupported, not executable. - if legacy selectors (
host.tap,host.swipe,host.text-input,host.wait) appear in schema output, treat it as a host contract regression before continuing real-project replay automation. - when deriving actions from
triton capabilities --json, trust only schema-alignednextActionvalues; embeddedpressis unsupported and should not be used as proof of device-level HID control. - after taps, submissions, and navigation, use
triton wait --text,triton wait --gone,triton wait --idle, or a safetriton wait --predicateinstead of fixed sleeps; - use
triton assert text-exists|text-not-exists <text> --jsonfor final pass/fail checks; add--within x,y,width,height,--role, or--countwhen labels repeat across headers, sidebars, and cells; - assert expected state through
wait, a secondax,find,screenshot, archive check, or a freshevidencebundle.
- Store outputs under
/tmpduring iteration, then copy only durable screenshots or docs into the correctdocs-linhay/spaces/<space-key>/location when the result is worth keeping. - Before sharing evidence outside the real app repo, sanitize project and personal information:
- replace private project names, app names, bundle IDs, team IDs, organization names, user names, account IDs, email addresses, phone numbers, local usernames, internal domains, and absolute private paths with stable placeholders;
- keep platform/tool versions, TritonKit version, command names, error codes, redacted route shape, and minimal sanitized snippets needed for reproduction;
- do not attach full private logs, screenshots with personal data, unredacted
.tritonevidence,.tritonplan,.xcresult, HDC/Simulator dumps, app archives, or credentials.
- If the real app exposes a missing TritonKit capability, unclear behavior, or bug, use
tritonkit-dev-feedbackand file/prepare the GitHub issue directly after redaction.
Real-Project Smoke Issue Closure
Use this checklist before commenting on or closing a real-project smoke issue such as iOS one-command smoke, Xcode occupancy diagnostics, WebView route checks, Harmony host-side smoke, or simulator takeover slices.
- Confirm the implementation is on
mainand pushed toorigin/main; reference the exact commit hash in the issue comment or session notes. - Confirm the relevant CLI schema exposes the capability, for example
triton schema --command smoke --json,triton schema --command xcode --json,triton schema --command app --json, ortriton schema --command webview --json. - Run the narrow unit or mock tests that own the orchestration and error shape.
- Run at least one structured host/runtime verification that exercises the user-facing command. For iOS one-command smoke this means
triton smoke ios ... --json; for open-url readiness it meanstriton app open-url <url> --wait-ready --snapshot --json; for Harmony host smoke this means the HDC-backeddevice/app/ax/wait/screenshotchain orsmoke harmonywhen available. - Treat host action acknowledgements as submission evidence only.
simctl openurl, HDCaa start,xcode run, tap, launch, or install success does not close a business smoke issue until a laterwait,assert, snapshot, screenshot, or evidence result proves the expected app state. - Attach or summarize evidence after redaction. Public comments must avoid real app names, bundle IDs, team IDs, private paths, screenshots with personal data, full logs, credentials, and unredacted
.tritonevidence,.xcresult, or HDC/Simulator dumps. - Update the owning
docs-linhay/spaces/<space-key>/README.mdor technical note with the current state, including which issues are still open. - Write memory for the decision, closure criteria, residual risks, and follow-up issues.
- Run docs/skill sync for pure documentation closures, or the full relevant test gate for code closures.
- Only close the issue once the issue-specific closure criteria are met. Keep epics such as simulator takeover open unless the scoped P0/P1 acceptance criteria are satisfied and remaining advanced scope has been split into follow-up issues or explicitly deferred in the closure comment.
Do not collapse multiple open issues into a single closure comment just because they share an orchestration layer. A shared implementation can close one issue and leave related issue slices open.
iOS App Integration Guide
Use this exact shape when the real app needs TritonKit embedded runtime access.
SwiftPM:
https://github.com/NeptuneKit/TritonKit.git
Add only the TritonKit product to the iOS app target. TritonKitShared is an internal shared-contract target pulled in transitively; app integrations should not select or import it directly. Keep every app-side source file that imports or starts TritonKit behind #if DEBUG; do not rely only on the package runtime guard.
SwiftPM supports configuration-scoped build settings, so TritonKit defines TRITONKIT_RUNTIME_ENABLED only for Debug package builds and keeps the embedded runtime no-op in Release. SwiftPM / Xcode package product dependencies still do not have a CocoaPods-style :configurations => ['Debug'] switch: the package product may remain attached to the target even though the runtime is disabled. If the production Release target must not link TritonKit at all, create a separate Debug-only app target or scheme and attach the TritonKit product only to that target.
CocoaPods during development. Do not add TritonKitShared explicitly; TritonKit resolves it transitively:
target 'YourApp' do
use_frameworks!
pod 'TritonKit',
:git => 'https://github.com/NeptuneKit/TritonKit.git',
:branch => 'main',
:configurations => ['Debug']
end
Create a dedicated Debug bootstrap file. For team apps, prefer an opt-in Debug bootstrap so ordinary Debug builds do not expose the runtime unless the developer explicitly enables it:
// TritonKitDebugBootstrap.swift
#if DEBUG
import Foundation
import TritonKit
enum TritonKitDebugBootstrap {
static func startIfEnabled() {
let arguments = ProcessInfo.processInfo.arguments
let environment = ProcessInfo.processInfo.environment
let isEnabled = arguments.contains("--triton-enabled")
|| environment["TRITON_ENABLED"] == "1"
|| UserDefaults.standard.bool(forKey: "TRITON_ENABLED")
guard isEnabled else { return }
TritonKit.shared.start { config in
config.endpoint = .environment()
config.autoReconnect = true
config.features = [.hierarchy, .accessibility, .input]
config.redaction.secureText = .lengthOnly
config.redaction.collectClipboard = false
config.redaction.collectNetwork = false
config.redaction.collectLogs = false
config.appIdentity = .init(name: "YourApp", tags: ["debug", "opt-in"])
}
}
static func stop() {
TritonKit.shared.stop()
}
}
#endif
Enable it from Xcode with launch argument --triton-enabled, environment variable TRITON_ENABLED=1, or Debug-only user default TRITON_ENABLED=true. config.endpoint = .environment() reads TRITON_HOST / TRITON_PORT and falls back to 127.0.0.1:19421. Use TritonKit.shared.start { config in config.endpoint = .device("192.168.1.20", port: 19421) } when a physical device needs to connect to a Mac LAN address.
Preferred facade APIs:
| Need | API |
|---|---|
| Start with environment fallback | TritonKit.shared.start() |
| Start with explicit local CLI port | TritonKit.shared.start(.local(port: 19421)) |
| Start from environment variables | TritonKit.shared.start(.environment()) |
| Start from a device to a Mac LAN address | TritonKit.shared.start(.device("192.168.1.20", port: 19421)) |
| Start with advanced options | TritonKit.shared.start { config in ... } |
| Stop the debug runtime | TritonKit.shared.stop() |
| Observe connection state | TritonKit.shared.onStateChange { state in ... } |
| Observe connection errors | TritonKit.shared.onError { error in ... } |
For advanced debug bootstrap code, keep the same file-level #if DEBUG guard and configure the facade in one closure:
#if DEBUG
TritonKit.shared.start { config in
config.endpoint = .device("192.168.1.20", port: 19421)
config.autoReconnect = true
config.features = [.hierarchy, .accessibility, .input]
config.redaction.secureText = .lengthOnly
config.appIdentity = .init(name: "YourApp", tags: ["smoke"])
}
#endif
Observe connection status without implementing a full delegate:
#if DEBUG
enum TritonKitDebugObservers {
private static var stateToken: TritonKit.ObservationToken?
private static var errorToken: TritonKit.ObservationToken?
static func start() {
stateToken = TritonKit.shared.onStateChange { state in
print("TritonKit state:", state)
}
errorToken = TritonKit.shared.onError { error in
print("TritonKit error:", error)
}
}
}
#endif
Retain observation tokens for as long as callbacks are needed, and call cancel() when an observer should be removed. start retains the default request handler internally; only use the lower-level delegate / connect(host:port:) API when you need a custom delegate or custom message routing.
Call the bootstrap only from a guarded app entry point:
#if DEBUG
TritonKitDebugBootstrap.startIfEnabled()
#endif
Harmony App Integration Guide
Use this shape when the real app needs Harmony / DevEco validation.
Host-side Harmony checks do not require any app package dependency:
triton device doctor --platform harmony --json
triton device list --platform harmony --json
triton device wait-ready --device <hdc-target> --json
triton app inspect --platform harmony --bundle <bundle> --target <hdc-target> --json
triton app install --device <hdc-target> --hap <debug-signed.hap> --json
triton app launch --device <hdc-target> --bundle <bundle> --ability <ability> --json
triton app open-url --device <hdc-target> --bundle <bundle> --ability <ability> '<url>' --json
triton ax --platform harmony --target <hdc-target> --output /tmp/<case>-layout.json --json
triton wait --platform harmony --target <hdc-target> --text '<text>' --timeout 15 --json
triton tap '<text>' --platform harmony --target <hdc-target> --json
triton screenshot --device <hdc-target> --output /tmp/<case>.jpeg --json
triton smoke harmony --device <hdc-target> --bundle <bundle> --ability <ability> --open-url '<url>' --wait-text '<text>' --screenshot /tmp/<case>.jpeg --evidence /tmp/<case>.tritonevidence --json
When multiple HDC targets are Connected, pass --device <alias-or-id> or an explicit --target; ambiguous_target is the expected machine-readable failure.
Host-side layout and screenshot artifacts may contain private UI data; inspect or summarize them before attaching evidence to public issues.
For Harmony embedded SDK work, keep the TritonKit brand separate from the OHPM package id. The actual package id and ArkTS import path are lowercase:
tritonkit
Until the Harmony package is published, use the aligned harmony-TritonKit source/HAR for validation. Keep the app integration Debug-only. Release builds must compile to disabled/no-op behavior and must not collect UI, screenshots, logs, route state, or action data.
Business semantics are not generic HAR capabilities. Route, responder, and semantic action state should come from app provider hooks. If providers are not registered, unsupported_runtime_scope is the correct runtime result; if the manifest marks those capabilities supported without providers, file a bug.
For a standalone Harmony embedded runtime before it is connected through triton serve, use direct runtime checks:
triton device runtime-url --device harmony-a --probe-manifest --json
triton runtime manifest --runtime-base-url http://127.0.0.1:28767 --json
triton state route --runtime-base-url http://127.0.0.1:28767 --json
triton snapshot --runtime-base-url http://127.0.0.1:28767 --json
triton ledger --runtime-base-url http://127.0.0.1:28767 --jsonl
triton set-text "密码" "$TRITON_PASSWORD" --secure --runtime-base-url http://127.0.0.1:28767 --json
For the Harmony demo, 28767 is the host-access embedded runtime port exposed through HDC fport; 18765 is only the demo device-to-host gateway fallback port.
CLI Install Contract
Use Homebrew for real-project adoption checks by default:
brew install NeptuneKit/tap/triton
brew update
brew upgrade triton
Use the local release CLI only while TritonKit is pre-release, while validating unreleased source changes, or when Homebrew / GitHub Release assets are unavailable:
swift build --package-path CLI --scratch-path .build/cli -c release --product triton
.build/cli/release/triton version --json
When installing that local build into ~/.local/bin/triton or another existing PATH location, avoid overwriting a path that may be backing a running triton serve process. Stop the server first, or use atomic replacement:
swift build --package-path CLI --scratch-path .build/cli -c release --product triton
cp .build/cli/release/triton ~/.local/bin/triton.new
mv ~/.local/bin/triton.new ~/.local/bin/triton
triton version --json
Homebrew installs only the macOS CLI. The app-side embedded runtime still comes from SwiftPM or CocoaPods and must remain DEBUG-only.
Release assets live in NeptuneKit/TritonKit GitHub Releases and include arm64/x86_64 CLI archives plus tritonkit_checksums.txt. The Homebrew tap is updated from those release assets after v* tag releases. If the release or tap is unavailable in a test environment, do not fail the regression setup on Homebrew; use the local release CLI and file a TritonKit issue with the missing distribution evidence.
Boundaries
- Do not commit or revert real app repo changes unless the user explicitly asks.
- Do not publish real app identity, private bundle IDs, personal accounts, user names, emails, internal hosts, absolute private paths, or unredacted evidence in TritonKit issues.
- Inspect evidence manifests, screenshot pixels, and artifact filenames before attaching them to public issues. If redaction cannot be verified, summarize the evidence instead.
- Do not treat a successful tap as completion; verify the resulting app state.
- Do not add Web/Wails UI to satisfy real-project needs when CLI/HTTP can provide the contract.
- System alerts and SpringBoard-level controls remain outside embedded runtime scope; expect
runtime_ui_interruptedor unsupported errors. - If the requirement becomes product work, create or update the corresponding
spacebefore implementation.
Existing Regression Entrypoints
- Generic complex harness:
docs-linhay/scripts/verify-complex-harness.sh - Intent CLI smoke:
docs-linhay/scripts/verify-intent-cli-smoke.sh - Overloaded real-app smoke:
docs-linhay/scripts/verify-overloaded-triton-smoke.sh
Replay Plan Notes
.tritonplanschema version 1 supportstap,paste,type,clear,wait,screenshot, andevidence.- Use
${variable}placeholders for account names, passwords, hosts, or output paths. - Use
secure: trueon password-likepasteortypesteps; replay summaries must redact values. - Prefer an
evidencestep at the end of a reused smoke flow so the final state is attachable to issues and regression reports. - For stale-list regressions, pair
capturewithassert text-not-exists <stale text> --within <right-list-bounds>so the report contains both artifacts and a machine-readable pass/fail result.