chore(cli): remove Slack, Agent Studio, Air, UI and Chat#121
Merged
Conversation
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.
AaronDDM
approved these changes
Jul 20, 2026
qasim-nylas
self-requested a review
July 20, 2026 23:22
qasim-nylas
approved these changes
Jul 20, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What
Removes five CLI surfaces and everything that existed only to serve them.
nylas slack(+slalias)internal/cli/slack/,internal/adapters/slack/,internal/ports/slack.go,internal/domain/slack.gonylas agent studiointernal/studio/(server, handlers, embedded JS/CSS/templates)nylas air(port 7365)internal/air/nylas ui(port 7363) +nylas demo uiinternal/ui/,internal/cli/demo/ui.gonylas chat(port 7367)internal/chat/Also removed because nothing else used them:
internal/webguard/— air, ui and chat were its only consumerstests/— the entire Playwright harness; every project and helper targeted a removed UI, and CI never invoked itgithub.com/slack-go/slackdependencytest-air*,test-e2e*,test-playwright*) plus theci-fullandtest-cleanuphooks into themnylas tuiandnylas demo tuiare 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
7a9106f0bd0a0a658f2c7ce60b5aTestCLI_WebhookLifecyclealways skipFixes 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.ErrHelpfor a non-runnable parent before it validates args, sonylas agent studioandnylas demo uiprinted help and reported success for commands that no longer exist. Both parents now setArgs: cobra.NoArgsand aRunEreturningcmd.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.shmatched staged.jsonpaths without excluding deletions, so removing the test fixtures failedmake ciwith "Sensitive file staged". A deleted file cannot leak its contents;--diff-filter=dexcludes deletions while still catching additions. This affected any commit deleting a JSON file, not just this one.TestCLI_WebhookLifecyclenever 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:
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. ArequireCommandListhelper 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-fullon the final tree: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.sumis now tidied. Removingslack-go/slackfromgo.modleft its hashes and those of itsgo-test/deeptest dependency behind, somake depsproduced an unrelated dirty diff for the next person to run it.internal/adapters/nylas/otp.go) and the Slack webhook shell examples in the docs are retained — both are independent of the removed integration..claudefiles were deleted because they documented only removed subsystems:agents/frontend-agent.md(scoped to the Air and UI frontends) andshared/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.docs/ARCHITECTURE.mdrather 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 ondomain.internal/adapters/nylas/demohas no importers and had none before this branch. Left in place as pre-existing dead code, out of scope here.make ci-fullwere not run.