app.nzapp
AppsProjectsReposPullsChatIntegrationsGatewayModelsEvalsToolsDatasetsMCPDeploysPricingBlogDocsAssistantsCharactersArtMusic
Sign inStart building
Agent stack
Cloud coding agentAgents SDKIntegrationsBrowser agentMonitors & auto-agentsSchedulersAgent skillsMCP serversDeep research
Models & API
AI GatewayModel catalogModel evalsModel spacesPlaygroundText to imageImage to 3DText to 3DMusic & SFXAudio editorMedia optimizerAI art & libraryChatAPI referenceSchemaBecome a provider
Compute & hosting
DeploysAddonsPostgres hostinggobed vector searchSite hostingAnalyticsCog GPU hostingRL trainingBuilds & CIWorkersTask queuesDomainsGit hosting
Tools
AI toolsDrawDiffusion canvasLive DrawWriteSheetsArtifactsVideo studioNotebooksDatasets
Learn
DocsBlogEval guidesPrompt libraryCLIAlternativesPapersAI charactersArt gallerySecurityConsulting
Company
PricingEnterpriseSettingsBillingStatusInvestorsCreate accountTerms of ServicePrivacy Policy
app.nzapp.nz

AI agent cloud for coding, deploys, model routing, and research. Built for teams shipping software.

Built in New Zealand by App AI NZ.

Social
X / TwitterGitHubYouTube
The app.nz network
GpuBrainPapersReading TimemojojojoNetwrckText-Generator.ioCodex InfinityOpenPathsCuteDSLAI Art GeneratorAIArt-Generator.artSiteSimSimplexGenDictatorFlowWebFiddleRing.nzChatGibidyBitBankExperimentFlowEvangelerHires.nzHow.nzV5 GamesAddicting Word GamesBig Multiplayer ChessWord SmashingreWord GameMultiplication Master
© 2026 App AI NZ Ltd. All rights reserved.All systems normalTermsPrivacy
Blog
July 7, 2026·4 min read·app.nz

Hardening route HTML, desktop deep links, and notebook paths

A small production hardening pass: serving generated SEO HTML, keeping desktop notebook paths inside the workspace, and fixing one-pass deep-link URL encoding.

Listen to this article

On-device voice

Uses the voice built into your browser; no article text leaves this page.

Audio narration is not supported by this browser.

Small production regressions usually come from boundaries that almost line up: the static build knows about a route, the server has a narrower allowlist; a protocol URL is already decoded, the fallback encoder treats it as raw percent text; an editor path resolver is hardened, but a neighboring notebook endpoint joins paths directly.

This pass tightened those boundaries in three places.

Route-specific HTML has to survive production

The site build emits route-specific HTML for indexable pages so crawlers see the right title and description. That includes generated comparison and tool pages such as /alternatives/vercel and /tools/gpu-cost-calculator.

The production server already served prerendered single-segment pages, plus /ai/<slug> and /docs/<slug>. The sitemap and prerender bundle had moved ahead of that allowlist, so new two-segment tool and alternatives pages could fall back to the generic app shell.

The fix was deliberately small: keep traversal rejection, keep the one-level depth limit, and extend the nested-route prefix allowlist to the generated sitemap families. A regression test now creates real dist/tools/.../index.html and dist/alternatives/.../index.html files and proves the server returns those exact pages.

Notebook paths use the same workspace boundary as the editor

The desktop bridge editor already resolves paths through a workspace-aware helper that rejects .. escapes and symlinks that resolve outside the selected workspace. Notebook open/save accepted relative paths too, but it joined them to the workspace and then continued with the resulting absolute path without rechecking containment.

Notebook path resolution now delegates relative paths to the same workspace resolver before any local read or cloud artifact upload. Absolute paths still work for files a user explicitly selected, but relative notebook paths stay inside the active workspace. The bridge test covers the practical case: ../outside.py is rejected before cloud:true can upload it.

Deep-link fallback should encode exactly once

Desktop protocol links can arrive with escaped query values, for example path=docs/My%20File%23v1.md. The parser decodes that into path segments. The browser fallback then pre-escaped each segment and assigned the result to URL.Path, which made URL.String() escape the percent signs again.

The optimized version validates decoded segments, assigns raw segments to URL.Path, and lets Go's URL encoder do the single final escape. That keeps links with spaces, #, and % stable when a desktop handoff falls back to the local browser shell.

The pattern is the same in all three fixes: one authority owns each boundary. The sitemap and prerender bundle define which marketing routes are indexable, the workspace resolver owns local relative paths, and net/url owns URL escaping.

Build what you just read

Ship agents, models, and apps on one cloud.

Start with free credits, then use the same platform from the web app, CLI, desktop app, or MCP.

Start building freeRead the docs

Keep reading

BYOK provider keys in the model gateway

How app.nz lets users bring provider keys while keeping routing unified, validating providers, preferring user keys, hiding full secrets, and avoiding open-relay behavior.

How we built isolated containers for agents and CI

The app.nz isolation model: per-run Docker networks, per-step containers, service sidecars, temp Docker auth, label cleanup, timeouts, and remote machines for bigger blast-radius boundaries.

Inkling: Thinking Machines’ open-weights model is built to be customized

Inside Inkling’s 975B MoE architecture, controllable reasoning, multimodal training, Apache 2.0 release, Tinker serving limits, and the new direct app.nz gateway route.