Skip to content

chore(cli): remove Slack, Agent Studio, Air, UI and Chat#121

Merged
qasim-nylas merged 4 commits into
mainfrom
chore/remove-slack-agent-studio
Jul 20, 2026
Merged

chore(cli): remove Slack, Agent Studio, Air, UI and Chat#121
qasim-nylas merged 4 commits into
mainfrom
chore/remove-slack-agent-studio

Conversation

@mqasimca

@mqasimca mqasimca commented Jul 20, 2026

Copy link
Copy Markdown
Collaborator

What

Removes five CLI surfaces and everything that existed only to serve them.

Surface Package(s)
nylas slack (+ sl alias) internal/cli/slack/, internal/adapters/slack/, internal/ports/slack.go, internal/domain/slack.go
nylas agent studio internal/studio/ (server, handlers, embedded JS/CSS/templates)
nylas air (port 7365) internal/air/
nylas ui (port 7363) + nylas demo ui internal/ui/, internal/cli/demo/ui.go
nylas chat (port 7367) internal/chat/

Also removed because nothing else used them:

  • internal/webguard/ — air, ui and chat were its only consumers
  • tests/ — the entire Playwright harness; every project and helper targeted a removed UI, and CI never invoked it
  • Slack credential loading, prompts, tools, approvals and execution paths in Chat
  • The github.com/slack-go/slack dependency
  • 11 Makefile targets (test-air*, test-e2e*, test-playwright*) plus the ci-full and test-cleanup hooks into them

nylas tui and nylas demo tui are unaffected — the terminal UI stays.

Why

These are no longer intended CLI surfaces. Removing complete vertical slices avoids leaving unused credentials, dependencies, web routes, or documentation behind.

Commits

7a9106f Remove Slack and Agent Studio
0bd0a0a Tidy go.sum, harden removal tests, drop stale doc counts
658f2c7 Remove Air, UI and Chat web surfaces
ce60b5a Fix DNS race that made TestCLI_WebhookLifecycle always skip

Fixes worth reviewing

These are behaviour changes rather than deletions, and are the parts most worth a careful look.

Removed commands were exiting 0. Cobra returns flag.ErrHelp for a non-runnable parent before it validates args, so nylas agent studio and nylas demo ui printed help and reported success for commands that no longer exist. Both parents now set Args: cobra.NoArgs and a RunE returning cmd.Help(), so unknown subcommands exit 1 while the bare command still prints help and exits 0.

The security scan false-positived on deletions. scripts/security-scan.sh matched staged .json paths without excluding deletions, so removing the test fixtures failed make ci with "Sensitive file staged". A deleted file cannot leak its contents; --diff-filter=d excludes deletions while still catching additions. This affected any commit deleting a JSON file, not just this one.

TestCLI_WebhookLifecycle never actually ran. It self-skipped with "cloudflared tunnel did not become externally reachable", which read like a network problem. Cloudflare publishes the quick-tunnel DNS record a few seconds after cloudflared prints the URL (measured: URL at ~6s, record live at ~10s), and there is no wildcard on *.trycloudflare.com. The test probed the instant it parsed the URL, landed in that gap, got NXDOMAIN, and the system resolver cached that negative answer for longer than the 60s retry loop ran — so every retry read the poisoned entry and the loop could never recover. Delaying only the first lookup fixes it; the probe error is also no longer discarded, since that is what made it hard to diagnose.

Measured against both resolvers:

t=7s   system: NXDOMAIN | 1.1.1.1: NXDOMAIN        (not published yet)
t=10s  system: NXDOMAIN | 1.1.1.1: 104.16.231.132  (published)
t=40s  system: NXDOMAIN | 1.1.1.1: 104.16.231.132  (still poisoned)

The test now exercises create/show/update/delete against the live API for the first time. It has presumably been silently skipping in CI for a long time, so it can now genuinely fail if webhooks break.

Removal tests could pass vacuously. The HelpOmits* tests assert only that a command is absent from stdout, which an empty stdout satisfies trivially. A requireCommandList helper now asserts the command list actually rendered first. Verified by feeding it empty output: it fails where it previously passed.

Regression coverage

Added and wired into make test-cli-regressions: TestCLI_SlackRemoved, TestCLI_SlackAliasRemoved, TestCLI_HelpOmitsSlack, TestCLI_AgentStudioRemoved, TestCLI_AgentsStudioRemoved, TestCLI_AgentHelpOmitsStudio, TestCLI_WebUIsRemoved (air/ui/chat/demo ui), TestCLI_HelpOmitsWebUIs, TestCLI_DemoHelpOmitsUI.

Testing

make ci-full on the final tree:

12,363 passed · 0 failed · 152 skipped

fmt · vet · lint · unit · race · security · govulncheck · CLI regressions · agent integration · full integration suite · resource cleanup — all green. The 152 skips are pre-existing environmental ones (Ollama unavailable, tests gated behind flags).

Notes

  • go.sum is now tidied. Removing slack-go/slack from go.mod left its hashes and those of its go-test/deep test dependency behind, so make deps produced an unrelated dirty diff for the next person to run it.
  • Generic Slack OTP recognition (internal/adapters/nylas/otp.go) and the Slack webhook shell examples in the docs are retained — both are independent of the removed integration.
  • Documentation swept across 22 files. Two .claude files were deleted because they documented only removed subsystems: agents/frontend-agent.md (scoped to the Air and UI frontends) and shared/patterns/playwright-patterns.md. The Playwright and CSS reminders were dropped from .claude/hooks/context-injector.sh — no browser JS or CSS remains in the repo.
  • Stale hardcoded file counts were removed from docs/ARCHITECTURE.md rather than re-derived. They had drifted well past this change (ports claimed 6 files against 23 actual, adapters 12 directories against 20) and the doc contradicted itself on domain.
  • internal/adapters/nylas/demo has no importers and had none before this branch. Left in place as pre-existing dead code, out of scope here.
  • Credentialed live integration suites beyond those in make ci-full were not run.

qasim-nylas and others added 4 commits July 20, 2026 16:26
Follow-ups from review of the Slack / Agent Studio removal.

go.sum: run go mod tidy. Removing slack-go/slack from go.mod left its
hashes plus those of its go-test/deep test dependency behind, so `make
deps` produced an unrelated dirty diff for the next person to run it.

Regression tests: add requireCommandList. The HelpOmits* tests assert
only that a command is absent from stdout, and an empty stdout satisfies
that trivially - if help output ever stopped landing on stdout they would
pass while verifying nothing. Verified by feeding the check empty output:
it now fails where it previously passed. Also drop the unreachable
"\nslack" clause; cobra indents commands by two spaces, so only
"\n  slack" could ever match.

ARCHITECTURE.md: remove hardcoded file counts. They had drifted well past
this change - ports claimed 6 files against 23 actual, adapters 12
directories against 20, nylas/ 94 against 81 - and the doc contradicted
itself on domain (27 in the tree, 28 in the layer section). Also drop
ports/utilities.go from the interface list; no such file exists.
Removes the three localhost web interfaces and everything that existed
only to serve them:

- nylas air  (internal/air, port 7365)
- nylas ui   (internal/ui, port 7363)
- nylas chat (internal/chat, port 7367)
- nylas demo ui (internal/cli/demo/ui.go)
- internal/webguard - air, ui and chat were its only consumers
- tests/ - the Playwright harness tested nothing else, and CI never ran it
- 10 Makefile targets (test-air, test-e2e-*, test-playwright-*) plus the
  ci-full and test-cleanup hooks into them

Two defects surfaced while wiring up the removal:

nylas demo ui exited 0. The demo command had no RunE, so cobra returned
flag.ErrHelp before ValidateArgs and printed help for a subcommand that
no longer exists - a removed command that looked like it succeeded. Same
fix already applied to `agent`: Args: cobra.NoArgs plus RunE returning
cmd.Help(). Bare `nylas demo` still prints help and exits 0.

The security scan failed on this change. scripts/security-scan.sh matched
staged .json paths without excluding deletions, so removing the test
fixtures tripped "Sensitive file staged". A deleted file cannot leak its
contents; --diff-filter=d excludes deletions while still catching
additions. This affected any commit deleting a JSON file, not just this
one.

Adds TestCLI_WebUIsRemoved, TestCLI_HelpOmitsWebUIs and
TestCLI_DemoHelpOmitsUI to the CLI regression target.

Docs: swept 21 files. Deleted .claude/agents/frontend-agent.md and
.claude/shared/patterns/playwright-patterns.md, which documented only the
removed subsystems, and dropped the CSS/Playwright reminders from
.claude/hooks/context-injector.sh - no CSS or browser JS remains in the
repo. nylas tui and nylas demo tui are unaffected.
…s skip

TestCLI_WebhookLifecycle never actually ran its create/show/update/delete
assertions. It self-skipped with "cloudflared tunnel did not become
externally reachable within 60s", which read like a network or cloudflared
problem. It was neither.

Cloudflare publishes the quick-tunnel DNS record a few seconds AFTER
cloudflared prints the URL - measured on this repo: URL at ~6s, record
live at ~10s. There is no wildcard on *.trycloudflare.com, so a lookup
inside that window returns NXDOMAIN. The test began probing the instant it
parsed the URL, landing squarely in the gap, and the system resolver then
cached that negative answer for longer than the 60s retry loop runs. Every
later attempt read the poisoned cache entry, so the loop could never
recover no matter how long it ran.

Measured, with the tunnel hostname resolved against both resolvers:

  t=7s   system: NXDOMAIN | 1.1.1.1: NXDOMAIN     (not published yet)
  t=10s  system: NXDOMAIN | 1.1.1.1: 104.16.231.132  (published)
  t=40s  system: NXDOMAIN | 1.1.1.1: 104.16.231.132  (still poisoned)

Delaying only the first lookup to t=20s, changing nothing else, resolves
immediately and the challenge returns 200 on the first attempt. Retrying
harder cannot fix this; not asking before the record exists is the only
thing that does.

Also stops discarding the probe error. The loop threw away the result of
client.Get, so the skip message could not distinguish a DNS failure from
an HTTP error - which is what made this expensive to diagnose. The last
failure is now reported in the skip message.

Verified: three consecutive uncached runs pass end to end (32.5s, 28.1s,
26.2s), exercising create, show, update and delete against the live API.
Previously every run skipped.
@qasim-nylas qasim-nylas changed the title chore(cli): remove Slack and Agent Studio chore(cli): remove Slack, Agent Studio, Air, UI and Chat Jul 20, 2026
@qasim-nylas
qasim-nylas self-requested a review July 20, 2026 23:22
@qasim-nylas
qasim-nylas merged commit b564e79 into main Jul 20, 2026
9 of 10 checks passed
@qasim-nylas
qasim-nylas deleted the chore/remove-slack-agent-studio branch July 20, 2026 23:24
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants