Opcua cli
Interact with OPC UA servers from the terminal using php-opcua/opcua-cli. 11 single-shot commands — browse, read, write, watch values in real time, explore the address space with an interactive TUI, discover endpoints, manage server certificate trust, generate typed PHP classes from a NodeSet2.xml, dump a server's address space to NodeSet2.xml. Pipe-friendly JSON output, no framework dependencies. Use this skill whenever the user wants to script OPC UA from a shell, debug a server interactively, generate PHP from a vendor's NodeSet2.xml, or set up CI checks against an OPC UA endpoint.From its SKILL.md
npx -y skills add php-opcua/ai-skills --skill opcua-cliAssembled from the repository path, not quoted from the project. Check it against their README if it does not work.
2 things to look at
- no licenseNo license file was found in the repository. Code published without one is not open source by default, so using it at work is a question for whoever answers licensing questions where you are.
- 0 stars0 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.
What its file declares
Copied from the file, not written here
The file declares its own license as MIT. That is the author’s claim about this one file, and it is not the same thing as the license GitHub reports for the repository, which is listed with the other numbers below.
SKILL.md
13.7 KB, ~3.5k tokens by cl100k_base, as published. Nobody here has run it
php-opcua/opcua-cli — v4.4.0 skill
A pure-PHP, no-framework CLI tool for OPC UA. Wraps php-opcua/opcua-client into 11 composable single-shot commands. Every command supports --json for piping into jq / Unix tools, every connection method (auth, security, cert paths) is the same across commands, and the explore command opens a full-screen TUI for ad-hoc address-space browsing.
When to use this skill
Activate when the user wants to:
- Probe an OPC UA server from a shell (
opcua-cli endpoints opc.tcp://server:4840) - Read / write / watch process variables without writing PHP code
- Browse / explore the address space interactively (TUI) or scriptably (JSON)
- Generate typed PHP classes from a vendor's NodeSet2.xml (
generate:nodeset) - Export a server's address space to NodeSet2.xml (
dump:nodeset) - Set up CI integration tests that read a known node and assert a value
- Manage the per-user trust store (
trust,trust:list,trust:remove) - Pipe OPC UA data into
jq,awk, Telegraf, monitoring scripts
Do NOT activate for: building a long-running OPC UA service (use opcua-client or opcua-session-manager directly), library-level integration (use opcua-client), or framework-bound integration (use laravel-opcua / symfony-opcua).
The 60-second mental model
$ opcua-cli <command> <endpoint> [<nodeId> | <args>] [--security-policy=...] [--username=...] [--json] [--debug-*]
│
▼
Application (src/Application.php) — registers 11 commands, parses argv via ArgvParser
│
▼
Command (one of 11 in src/Commands/) — implements CommandInterface
│
▼
CommandRunner (src/CommandRunner.php) — builds the Client (security, trust, timeout)
│
▼
php-opcua/opcua-client Client.connect() → service call → typed result
│
▼
OutputInterface (ConsoleOutput tree/text | JsonOutput machine-readable)
│
▼
stdout (data) | stderr (diagnostics) → caller's pipeline
Three things to know:
- No framework. Not Symfony Console. Argument parsing is a custom
ArgvParser, command dispatch is a customCommandRunner. The only runtime dep beyondopcua-clientisphp-tui/php-tui(only loaded if you runexplore). - Two output modes for every command: human-readable (
ConsoleOutput, default — colored tree / table) and machine-readable (--json→JsonOutput). The JSON shape is stable and documented per-command; use it for scripts. - Stdout for data, stderr for diagnostics.
--debug-stderrroutes log lines to stderr so piping the data output throughjqstays clean. The TUI command (explore) takes over the whole terminal and rejects--json/--debug(they'd corrupt the display).
Quick start (90% of use cases fit this shape)
# Probe — what does this endpoint speak?
opcua-cli endpoints opc.tcp://server.example:4840
# Read the canonical "is the server alive?" node
opcua-cli read opc.tcp://server.example:4840 'i=2259' # Server.ServerStatus.State
# Read with JSON output → pipe to jq
opcua-cli read opc.tcp://server.example:4840 'ns=2;s=Temp' --json | jq -r '.value'
# Browse one level
opcua-cli browse opc.tcp://server.example:4840 'i=85' # Objects folder
# Browse a tree, 3 levels deep
opcua-cli browse opc.tcp://server.example:4840 /Objects --recursive --depth=3
# Open the interactive TUI (Linux/macOS only)
opcua-cli explore opc.tcp://server.example:4840
# Write a value
opcua-cli write opc.tcp://server.example:4840 'ns=2;s=Setpoint' 42.5 --type=Double
# Watch a value change in real time
opcua-cli watch opc.tcp://server.example:4840 'ns=2;s=Temp' # subscription mode (default)
When to load deeper references
| If the task involves… | Read |
|---|---|
| Exact flags / JSON output shape for any of the 11 commands | references/COMMANDS.md |
| Security policy choice, certificates, mTLS, username/password, trust store | references/SECURITY.md |
The explore interactive TUI — keys, layout, debug-routing | references/EXPLORE.md |
generate:nodeset / dump:nodeset — code generation flows | references/CODEGEN.md |
| Pipe-friendly scripting, exit codes, JSON parsing, CI patterns | references/SCRIPTING.md |
| How the internals are wired (Application, ArgvParser, CommandRunner, Commands) | references/ARCHITECTURE.md |
| Debugging an unfamiliar error or generating wrong shell quoting | references/PITFALLS.md |
| Complete bash one-liners for common ops (cron probe, jq pipelines, CI gate) | assets/recipes.md |
The 11 commands
| Command | Description | Connects? |
|---|---|---|
browse <endpoint> [<nodeId>] | List references from a node (default i=85 Objects). Supports --recursive, --depth=N. | Yes |
read <endpoint> <nodeId> | Read an attribute (default Value). --attribute=Value|DisplayName|BrowseName|DataType|NodeClass|Description|AccessLevel|NodeId. | Yes |
write <endpoint> <nodeId> <value> | Write a value. --type=<BuiltinType> to skip auto-detect. | Yes |
watch <endpoint> <nodeId> | Stream value changes. Subscription mode by default; --interval=N switches to polling every N ms. | Yes |
explore <endpoint> | Full-screen TUI. ↑/↓ navigate, →/Enter expand, ← collapse/parent, r refresh, q/Esc quit. Linux/macOS only. | Yes |
endpoints <endpoint> | Discover server endpoints + their security policies / user token policies. | Yes (discovery — no session) |
generate:nodeset <file.NodeSet2.xml> | Emit PHP enums / DTOs / codecs / registrar / NodeId constants from a NodeSet2.xml. --output=PATH --namespace=NS. | No |
dump:nodeset <endpoint> | Read a server's address space and export as NodeSet2.xml. --output=FILE --namespace=N. | Yes |
trust <endpoint> | Connect, capture the server's certificate, store it in the trust store (TOFU). --trust-store=PATH --trust-policy=fingerprint|fingerprint+expiry|full. | Yes |
trust:list | List trusted certificates. --trust-store=PATH. | No |
trust:remove <thumbprint> | Remove a trusted certificate. --trust-store=PATH. | No |
Security options (every connection-aware command)
| Option | Short | Values |
|---|---|---|
--security-policy=POLICY | -s | None, Basic128Rsa15, Basic256, Basic256Sha256, Aes128Sha256RsaOaep, Aes256Sha256RsaPss, ECC_nistP256, ECC_nistP384, ECC_brainpoolP256r1, ECC_brainpoolP384r1 |
--security-mode=MODE | -m | None, Sign, SignAndEncrypt |
--cert=PATH | Client certificate (PEM) | |
--key=PATH | Client private key (PEM) | |
--ca=PATH | CA certificate (PEM) | |
--username=USER | -u | Username for username/password auth |
--password=PASS | -p | Password (avoid on shared hosts — visible to ps) |
--timeout=SECONDS | -t | Connection timeout (default 5 s) |
Global options (every command)
| Option | Short | Description |
|---|---|---|
--json | -j | Machine-readable JSON output (rejected by explore) |
--debug | -d | Debug log to stdout (rejected by explore and incompatible with --json piping) |
--debug-stderr | Debug log to stderr (safe with --json piping) | |
--debug-file=PATH | Debug log to a file | |
--help | -h | Show help (overall or per command: opcua-cli read --help) |
--version | -v | Show CLI version |
v4.4.0 alignment
Lock-step with php-opcua/opcua-client v4.4.0. The CLI binds to the core directly — no service layer in between — so every server-facing command benefits transparently from the v4.4 additions:
- New
aggregate/historyAggregate/historyInsert*/historyUpdate*/historyDelete*core methods are reachable from CLI flows that already touch history (but the CLI does NOT yet have first-classhistory/aggregatesubcommands — would be a v4.5+ candidate) - The HTTPS / Reverse Connect ext transports plug in via
ClientBuilder::setTransport()— invisible to the CLI surface, just works againstopc.https://endpoints once those packages are installed alongside - Pre-generated nodeset types (
php-opcua/opcua-client-nodeset) are loaded transparently when present (CLI auto-discovers registrars via the autoloader)
Idiomatic patterns AI agents should follow
-
Always quote NodeId strings in shell —
ns=2;s=Temphas a;that bash treats as a command separator. Use single quotes:'ns=2;s=Temp'. -
-j/--jsonfor any output you pipe tojq/awk/grep. Default human output has colors, padding, and tree-drawing characters that break parsing. -
--debug-stderrinstead of--debugwhen piping.--debugwrites to stdout and corrupts JSON. -
--type=<BuiltinType>on writes when you know the type — saves a read-before-write round trip. Without it, the CLI does an auto-detect read first. -
Use the
readcommand with--attribute=DataTypeto discover a node's type before writing. Cheap, no commit. -
trustbefore connecting securely to a new server —opcua-cli trust opc.tcp://server:4840pulls the cert into the user trust store, then subsequent commands honour--trust-policy. Without trust setup,--trust-policy=fingerprintconnections to that server fail. -
explorefor ad-hoc, scripts for repeated operations. The TUI is great for "what does this server have?", terrible for automation. For automation usebrowse --recursive --depth=N --jsonand parse withjq. -
--timeout=2for fast-fail probes in CI. The default 5 seconds is fine interactively but stretches CI gates. -
Don't use
--passwordfrom a shell. Prefer reading from a file:--password="$(cat /run/secrets/opcua_pwd)"(or use a config file inphp-opcua/laravel-opcua/symfony-opcuaintegrations). -
Exit codes matter:
0— success1— generic error (parse, validation, business logic)2— connection error (DNS, TCP, TLS, OPC UA handshake)3— authentication / security error4— service-level OPC UA error (StatusCode != Good)
Bash scripts can branch on these for selective retry.
Common pitfalls (read before generating code)
Don't write code that:
- Unquoted NodeIds in shell:
ns=2;s=Temp— bash parses;as a command separator --debugmixed with--jsonto stdout — debug lines corrupt the JSON outputexplorewith--jsonor--debug— explicitly rejected (would corrupt the TUI)- Hard-codes
~/.opcuaas trust-store path — different per-user; use$HOME/.opcuaor pass--trust-store=PATHexplicitly dump:nodesetagainst a huge server without--namespace=Nfilter — the export can run for minutes and produce >100 MiBgenerate:nodesetwriting intovendor/— generated code belongs in your application'ssrc/- Loops calling
opcua-cli read100 times — each call pays the connect handshake (~150 ms). Usewatchor a real PHP script viaopcua-client. watch --interval=10(polling every 10 ms) — hammers the server. Stick with subscription mode unless you have a reason.
Full catalog in references/PITFALLS.md.
Related packages in the php-opcua ecosystem
opcua-client— the OPC UA client library this CLI wraps. v4.4+ required.opcua-client-nodeset— pre-generated types for 51 OPC Foundation companion specs. Auto-discovered by the CLI (no extra config) when installed in the project.opcua-session-manager— daemon for cross-request session persistence. Not used byopcua-cli(each command is one-shot — no benefit). Use it only from long-lived applications.laravel-opcua/symfony-opcua— framework integrations. The CLI is a separate utility; framework integrations replace it for in-app code, but the CLI stays useful for ops / debugging / generation.uanetstandard-test-suite— Docker-based OPC UA test servers. Useful target for trying every CLI command locally.
Distribution forms
The CLI ships in three forms (all from the same source):
- Composer dep:
composer require php-opcua/opcua-cli→vendor/bin/opcua-cli - Global composer install:
composer global require php-opcua/opcua-cli→~/.composer/vendor/bin/opcua-cli(add toPATH) - PHAR / standalone binary:
box.json.distbuilds a single-file PHAR viabin/opcua-cli. Distributed via the GitHub Releases workflow (release-binaries.yml) — download a PHP-bundled binary for Linux / macOS / Windows.
Recommend vendor/bin for project-scoped use; global or PHAR for ops / CI-runner installs.
What ships with it: 8 files
62.5 KB alongside SKILL.md
assets/
- recipes.md8.4 KB
references/
- ARCHITECTURE.md9.1 KB
- CODEGEN.md7.2 KB
- COMMANDS.md8.8 KB
- EXPLORE.md6.0 KB
- PITFALLS.md8.2 KB
- SCRIPTING.md7.3 KB
- SECURITY.md7.4 KB