spatie/there-there-cli
A command-line tool for There There that lets you interact with the There There API from your terminal. Install it globally with Composer, log in per workspace profile, and manage tickets—list, show, reply, forward, and update—right from the CLI. Full docs at there-there.app.
Classification is the first decision. spatie/there-there-cli is not a package we require and use inside application code. It is a Laravel Zero standalone CLI shipped as a committed PHAR (builds/there-there), installed via composer global require, with one command per There There API endpoint generated from a bundled OpenAPI spec through spatie/laravel-openapi-cli. It competes with, rather than substitutes for, an in-app integration layer. Any roadmap item phrased as "integrate There There into our Laravel app" must be split into ops automation (this package qualifies) and runtime integration (it does not — that still requires our own HTTP client, retries, typed DTOs, and queued workers).
Architecture fit. The only viable pattern is shell-out: Laravel console commands, the scheduler, and CI jobs invoke there-there via Symfony\Component\Process\Process, parse JSON from stdout, and treat non-zero exit codes as failures. This fits well for reporting digests, SLA sweeps, escalation routing, bulk status/tag remediation, and on-call triage. It does not fit request-path work: every invocation is a fresh process with Composer-global binary resolution, no connection reuse, and no shared retry/backoff layer.
Strengths that materially reduce scope:
--profile and an X-Workspace-Id header (0.5.0). Multi-brand automation becomes a supported shape rather than bespoke token juggling.0600 on ~/.there-there/config.json, TLS verification on by default since 0.5.0 (relaxed only for localhost/127.0.0.1/*.test).there-there install-skill), relevant if we expect coding agents or on-call engineers to drive triage from a terminal.Technical risk, ordered by blast radius:
used. Mitigation: make --profile mandatory and asserted in every wrapper, never rely on ambient state.builds/ is what Composer installs and nothing rebuilds it automatically. 0.8.0 was tagged on a spec resync but shipped the 0.7.1 PHAR, so show-ticket was absent and stale get-tickets-ticket remained. Version numbers therefore do not reliably predict command surface. Mitigation: pin an exact version and run a smoke test asserting --version plus a known command set before any rollout.operationIds and have already been renamed (get-tickets-ticket → show-ticket, patch-company → update-company). Scripts authored against one version break on upgrade. Mitigation: pin, and contract-test the command surface in CI.~/.there-there/config.json (0600). Shared runners imply tokens at rest on a host. No documented environment-variable token injection — a blocking question.download-attachment corrupting non-JSON bodies; the framing line, trailing newline, and console formatter eating <...> bytes were upstream defects. Any parser must tolerate binary passthrough and should not assume stdout is always JSON. Whether errors go to stderr is unconfirmed.list-tickets is "paginated" but cursor/limit semantics and API throttling are not documented in the README. Bulk remediation as an N-process loop against an unknown quota is a real risk.Key questions for the vendor/owner before commitment:
~/.there-there/config.json, and is there a documented rotation procedure?Stack fit. Laravel scheduler + console commands wrapping Process is the natural home. No service provider, no facade, no queue integration — the package sits outside the app container. That is an advantage for blast-radius containment and a disadvantage for observability: no shared HTTP middleware means our logging, tracing, and retry semantics must be layered in the wrapper.
Migration path. Treat as greenfield ops tooling, not a port. There is nothing to migrate from; the decision is whether to build direct API clients versus adopting this binary. For read-heavy reporting and ad-hoc triage, the CLI wins on time-to-value (days, not sprints). For anything needing typed models, transactional retries, or per-request tracing, build the client — do not bend the CLI into that shape.
Compatibility. Require PHP and Composer available on every execution host, including CI images. Pin spatie/there-there-cli:0.8.2 (or newer verified build) explicitly; composer global require has no per-project lockfile, so pinning must be baked into the base image and asserted at boot. Verify the global Composer bin dir is on PATH in non-interactive shells — a classic silent failure in cron and CI contexts. Pin the profile name in every call site; do not depend on there-there use.
Sequencing (each stage gated):
get-me, list-tickets, show-ticket, list-ticket-activities against one workspace from a single engineer's machine. Confirm JSON shape stability and pagination behaviour. Gate: documented response schema and confirmed pagination flags.add-note-to-ticket, update-ticket-status with explicit --profile and a dry-run flag in our wrapper. Gate: peer review of every mutating call site and an audit log of what the CLI changed.install-skill only with a read-only scoped token and a documented prohibition on mutating commands.Maintenance. Two maintenance streams: the vendor's, which we do not control, and ours, which is the wrapper layer. Budget roughly one engineer-day per quarter for version review plus the cost of each upgrade's contract test. The 0.x line guarantees at least occasional breaking renames; assume one breaking upgrade per year. The stale-PHAR class of bug means we must independently verify behaviour post-install rather than trusting the changelog.
Support. MIT-licensed open source with no vendor SLA. There is no support contract to escalate to; issues surface as GitHub issues with no committed response time. Internal support burden is a runbook covering authentication, profile switching, token rotation, and the upgrade procedure — realistically half a day to write, and it must be written before the second engineer touches the tool.
Scaling. Scales linearly with invocation count, and invocation count is the cost unit: one process spawn plus one TLS handshake per API call. Fine for tens to low hundreds of calls per run; a full-backlog sweep of thousands of tickets becomes minutes of wall clock and a rate-limit hazard. There is no batching, no connection pooling, and no concurrency primitive — parallelism must come from our side, which then multiplies the rate-limit exposure. Realistic ceiling: single-workspace reporting and per-ticket operations, not bulk re-processing.
Failure modes and detection:
| Failure | Symptom | Detection | Containment |
|---|---|---|---|
| Expired/rotated token | 401 from any command | Nightly smoke job | Alert + rotation runbook |
| Wrong workspace | Mutation succeeds in wrong tenant | None from the CLI itself | Mandatory --profile, post-mutation audit |
| Stale PHAR after upgrade | Command missing or renamed | Contract test on command surface | Pin version, block upgrade until test passes |
| API throttle | Non-zero exit, message unclear | Wrapper exit-code classification | Backoff, per-run caps |
| Binary/non-JSON passthrough | Corrupt parsed output | Schema validation on parsed stdout | Reject and alert rather than act |
| Process/PATH failure | Command not found | Health check at job start | Bake bin dir into image/PATH |
The critical property is that failures must be loud. A wrapper that swallows non-zero exits or treats empty stdout as "no tickets" converts an outage into silent inaction on SLA breaches — that is the scenario worth designing against first.
Ramp-up. Low. An engineer familiar with CLIs and JSON is productive in under an hour; the skill file is a usable onboarding artifact in its own right. The non-obvious cost is guardrail education, not syntax: engineers must internalise that the default profile is ambient state, that version numbers do not imply command surface, and that mutating commands have no dry-run. Budget a short team walkthrough before the first mutation stage, and gate it on the runbook being written.
How can I help you explore Laravel packages today?