Use the raw cloud provider id for imported provider config and auth so synced removals and updates can reconcile against the same key. Preserve provider-family behavior by storing source metadata and using names where UI heuristics still need Anthropic/OpenAI detection.
Co-authored-by: src-opn <src-opn@users.noreply.github.com>
Keep workspace-managed providers aligned with the active cloud org on sign-in, launch, background sync, and Cloud settings open while declaring the sync interval in one place.
Co-authored-by: src-opn <src-opn@users.noreply.github.com>
Users were confused when adding or editing an LLM provider because the
display name was derived automatically from the catalog or pasted
config. This made it impossible to tell two keys for the same provider
apart (e.g. 'OpenAI personal' vs 'OpenAI prod').
- Add an explicit 'Name' field to the add + edit LLM provider forms in
ee/apps/den-web with a 'Give this key a name' prompt, preload the
current name when editing, and require a non-empty value before save.
- Require 'name' on the llm-provider write schema in ee/apps/den-api and
persist it verbatim instead of falling back to provider.name from the
models.dev catalog or the custom config JSON.
Verified end-to-end via Chrome DevTools MCP on the Den Docker stack;
screenshots captured under ee/apps/den-web/docs/screenshots/.
Co-authored-by: src-opn <src-opn@users.noreply.github.com>
* feat(den): let orgs restrict supported desktop versions
Give org settings a desktop version allowlist derived from the server-supported range so admins can block specific releases without exposing stale metadata.
* fix(den): simplify desktop version settings copy
Reduce the prominence of the supported-version helper text and remove the redundant summary box so the allowlist stays focused on the actual version choices.
---------
Co-authored-by: src-opn <src-opn@users.noreply.github.com>
* feat(app): enforce desktop restriction policies
Keep org desktop restrictions consistent in the desktop client by hiding blocked provider/model paths and syncing workspace config when Zen access is disabled.
* fix(app): persist provider disconnects in workspace config
Keep config-backed providers disabled through the same opencode.jsonc flow used by desktop restrictions so disconnecting OpenCode writes the workspace disabled_providers state reliably.
---------
Co-authored-by: src-opn <src-opn@users.noreply.github.com>
Treat legacy '/v1/orgs/:orgId/*' forwarding differently from API-key scoping so proxied requests can still hydrate a missing session active organization. This keeps older clients working across moved endpoints while preserving API-key behavior.
Co-authored-by: src-opn <src-opn@users.noreply.github.com>
* fix(den): support legacy org invitation routes
Restore the old org-scoped invitation paths and rehydrate sessions to a user's first organization when activeOrg is missing so older clients keep working. Include the shared types workspace in Den Docker images so the local verification stack can still build.
* fix(den): proxy legacy org-scoped routes
Route legacy '/v1/orgs/:orgId/*' requests into the new unscoped '/v1/*' handlers while preserving the current '/v1/orgs/...' endpoints. Pass the org id through middleware so old clients keep the intended workspace context and add coverage for the generic proxy behavior.
* refactor(den): trim invitation route churn
Drop the leftover invitation-specific handler extraction now that legacy org-scoped forwarding is handled generically in the org router. Keep the proxy behavior intact while returning the invitation routes closer to their original shape.
---------
Co-authored-by: src-opn <src-opn@users.noreply.github.com>
* feat(landing): SEO metadata, JSON-LD, H1 fixes, manifest
Raises the site's traditional SEO to match its strong agent-readiness
foundations (llms.txt, api-catalog, markdown negotiation).
Metadata:
- Root layout: canonical, og:type/siteName/locale, explicit robots
- Per-page canonical + openGraph.url on every route
- Rewritten titles/descriptions for /pricing, /enterprise, /den, /download
(previously 14-21 char titles and 51-73 char descriptions)
- /feedback and /starter-success marked noindex,follow
- /feedback removed from sitemap; /privacy and /terms demoted to 0.3
- Title dash normalized to em-dash site-wide
Headings:
- /den gains a real <h1> (was <h2> only — a11y + SEO bug)
- /enterprise H1 rewritten to be enterprise-specific (was a dup of home)
- /pricing H1 enriched; tier names promoted to <h2> in pricing-grid
- /download nav-card duplicate H2s demoted to spans
- lib/agent-markdown.ts H1s realigned with HTML for agent parity
Structured data:
- New components/structured-data.tsx helper
- Organization on every page (root)
- SoftwareApplication on / and /download
- Product with three Offers on /pricing
Manifest & perf:
- New app/manifest.ts
- Enterprise hero: 12MB PNG -> 1.1MB JPEG (1600px q70)
Old PNG left in public/ for a follow-up cleanup commit
* chore(landing): remove unused /den marketing page
Deletes the /den route and its components (LandingDen, DenHero) along
with every internal reference. The cloud product is still linked from
nav + footer, pointing at https://app.openworklabs.com.
- Removed from sitemap.ts, middleware.ts matcher, and agent-markdown
(both the markdown twin and the "Den (team workspace)" home mention)
- Removed from llms.txt routing list and site map
- Footer "Cloud" link now points to the external app (matches nav)
- Nav internal key renamed from "den" to "cloud" and type union updated
- WebMCP navigate_to destinations no longer advertise "den"
api-catalog still references "OpenWork Den API" since that's the API
product name, not the marketing page — untouched.
* fix(landing): point nav + footer Cloud link at /cloud redirect
Previous removal of /den hardcoded the external app URL into the nav
and footer. Switch to the /cloud internal path so the existing cloud
redirect is the single source of truth (and works consistently with
the rest of the internal links).
* docs(landing): restore Cloud mentions in llms.txt and agent-markdown
The previous /den removal also stripped every Cloud mention from the
agent-facing text. Restore them pointing at /cloud (which redirects to
https://app.openworklabs.com) so agents can still route users to the
hosted workspace.
* fix(landing): link Cloud directly to app.openworklabs.com, not /cloud
There's no /cloud route on the marketing site — the hosted app lives
at https://app.openworklabs.com. Point every Cloud link (nav, footer,
llms.txt, agent-markdown, WebMCP) at the real URL.
* feat(landing): replace Trust details link with Security Review CTA
The old small Trust details text link under the Book a call button got
lost. Surface it as a proper secondary CTA next to Book a call, and
rename to Security Review to set expectations for enterprise buyers.
Also updates the enterprise markdown twin to mirror the label.
* fix(landing): preserve og:type/siteName/locale/images on pages overriding openGraph
Next.js replaces (not merges) the openGraph object across layout/page
boundaries. Earlier per-page metadata added only og:url, which silently
wiped og:type, og:siteName, og:locale, and og:image off every page that
did so — exactly the fields the root layout relied on for defaults.
Introduce lib/seo.ts with a baseOpenGraph constant and spread it into
every per-page openGraph override. Caught by running the PR's test plan
against the dev server: 12 failing checks → 0 after this fix.
* feat(landing): rasterize SVG into favicon.ico + PNG icon set
Adds proper raster icons for browsers/OSes that don't render SVG
favicons (older Safari, Android home-screen, Windows taskbar):
- app/favicon.ico — 32×32, PNG-in-ICO container
- app/icon.png — 192×192
- app/apple-icon.png — 180×180
Uses Next.js App Router icon-file convention — Next auto-generates the
<link rel="icon"> / <link rel="apple-touch-icon"> tags, so the
manual icons: metadata block in app/layout.tsx is removed.
Manifest updated to advertise the 192×192 PNG (the Android PWA pick)
alongside the 180 apple-icon and the SVG mark.
All three PNGs generated from public/openwork-mark.svg with sharp,
centered on a white square canvas with ~10% padding so the mark
doesn't bleed to the edges at any size. Generator script at
/tmp/generate-favicons.mjs (not committed) — re-run any time the
source SVG changes.
* fix(landing): match /enterprise H1 styling + copy to /
The /enterprise hero H1 used slightly different Tailwind classes (mb-6,
leading-[1.05]) than the homepage H1 (mb-5, leading-[1.1]), giving a
visibly different type rhythm. Align to the home page classes.
Copy updated to 'A privacy-first alternative to Claude Cowork for your
org' — clearer positioning than 'OpenWork for the enterprise'. Mirrored
in the agent-markdown enterprise twin for parity.
* fix(landing): use 'organization' not 'org' in /enterprise H1
* fix(landing): restore original /enterprise hero subhead copy
* fix(landing): open Docs in a new tab from the main nav
Footer's Docs link already opens in a new tab; the top nav didn't. Add
an explicit newTab flag to the nav items array and honor it in both
the desktop and mobile menus so visitors keep the marketing tab open
while reading docs.
Adds three agent-readiness features on openworklabs.com:
- Markdown content negotiation: middleware serves hand-authored
markdown twins for /, /pricing, /enterprise, /den, /download, and
/trust when Accept: text/markdown outranks text/html. Sets
Content-Type: text/markdown; charset=utf-8, Vary: Accept, and an
X-Markdown-Tokens estimate. Browsers still get HTML by default.
- API catalog (RFC 9727): /.well-known/api-catalog returns an
application/linkset+json document pointing at api.openworklabs.com's
openapi.json, /docs/api-reference, /health, and llms.txt. Advertised
from the home page via the Link header.
- WebMCP: a client component calls navigator.modelContext.provideContext
on mount with four tools — navigate_to, open_enterprise_contact,
get_pricing_summary, and get_download_links. Submit-style mutations
are intentionally excluded; agents navigate users to forms instead of
posting on their behalf.
* feat(landing): make site agents-ready
Adds robots.txt with AI crawler rules and Content-Signal (ai-train=no,
search=yes, ai-input=yes), an RFC-compliant sitemap.xml, Link headers
pointing agents to /docs and the agent-skills index, and exposes the
workspace-guide skill at /.well-known/agent-skills/ with a sha256-verified
index.json.
* feat(landing): permit AI training in Content-Signal
* feat(landing): simplify robots.txt and add llms.txt navigation guide
Collapse robots.txt to a single User-agent: * Allow: / block (matching
the Huggingface pattern) — all per-bot entries had identical rules, so
the wildcard already covers them and future bots without maintenance.
Content-Signal remains permissive (ai-train=yes, search=yes, ai-input=yes).
Add llms.txt per the llmstxt.org spec — the main gap Cloudflare's
agent-readiness checklist identifies for this site. It tells agents how
to route users based on intent (download, pricing, enterprise, den),
what agents can do once OpenWork is installed, and how the cloud plan
differs from the desktop app.
* docs(landing): neutral llms.txt tone, drop feedback routing
Drop the routing entry that sends agents to /feedback — feedback should
come from humans, not agent-mediated submissions. Rephrase the agents
note from 'we want usage' to a neutral statement of what agents may do.
* refactor(app): remove hide_main_window function and update macOS window close behavior
Eliminate the hide_main_window function to streamline window management. Update the macOS behavior to exit the application when the main window is closed, aligning it with the behavior on Windows and Linux.
* surface openwork as main focused window onDock click
* refactor(app): remove hide_main_window function and update macOS window close behavior
Eliminate the hide_main_window function to streamline window management. Update the macOS behavior to exit the application when the main window is closed, aligning it with the behavior on Windows and Linux.
* surface openwork as main focused window onDock click
Introduce org-scoped marketplaces so teams can curate and share groups of plugins with consistent access rules. This adds the schema, admin routes, RBAC updates, and PRD coverage needed for marketplace-backed plugin catalogs.
Co-authored-by: src-opn <src-opn@users.noreply.github.com>
* fix(den-api): surface invitation email send failures instead of swallowing
Loops failures in sendDenOrganizationInvitationEmail and
sendDenVerificationEmail were being caught and logged at warn level,
so the HTTP handlers still returned 201 'Invitation created' even when
no email ever left the process. Ben observed this with two live
invitations: the DB row was pending, the UI showed it, but one of two
recipients never received the email and clicking resend re-ran the same
silent-failure path.
Root cause (from an explore audit):
- email.ts:129,132 swallowed non-2xx Loops responses and fetch throws.
- invitations.ts awaited the send and unconditionally returned 2xx.
- There is no 'skip email if user already exists' branch anywhere;
the Slack hypothesis was wrong. The failure mode is provider-side and
was invisible because of the swallow.
Changes:
- Introduce DenEmailSendError with a stable reason tagged union
(loops_not_configured | loops_rejected | loops_network).
- sendDenOrganizationInvitationEmail and sendDenVerificationEmail now
throw DenEmailSendError on failure. Dev-mode short-circuit is
preserved (still logs the payload and returns cleanly).
- POST /v1/orgs/:orgId/invitations catches DenEmailSendError, logs via
console.error with a stable [auth][invite_email_failed] prefix
(greppable across deployments), and returns 502
invitation_email_failed with a human-readable message and the
invitationId so the UI can correlate and offer a retry. The row is
left pending intentionally so the next submit becomes a real resend.
- Document the 502 response in the OpenAPI describeRoute.
Operator note: if LOOPS_TRANSACTIONAL_ID_DEN_VERIFY_EMAIL is unset the
signup OTP endpoint will now return a real error instead of silently
stranding the user at the OTP screen forever. This is intentional; the
previous behavior was a latent signup-breaking bug.
* fix(den-api): tolerate missing apps/desktop/package.json in Docker build
PR #1476 introduced a build step that reads apps/desktop/package.json to
bake in a default latest-app-version, but packaging/docker/Dockerfile.den
does not ship the Tauri desktop sources. As a result, the den-dev Docker
stack fails to build after the PR landed. Gracefully fall back to 0.0.0
(matching the runtime default) when the file is absent, and allow a
DEN_API_LATEST_APP_VERSION env override so deployers can still pin a
real value.
* test(den-api): add smoke script for invite email failure paths
scripts/smoke-email-failures.mjs exercises the DenEmailSendError paths
against the built dist/ of den-api. Ships with instructions so a
reviewer can rerun it inside the docker-compose den-dev container with
a single command.
Also parameterises OPENWORK_DEV_MODE in the den compose service so the
failure paths can be reached from outside the container when needed
(defaults to 1; override with OPENWORK_DEV_MODE=0 at compose time).
* feat(den-api): add PATCH /v1/orgs/:orgId to rename organization
- Owners can update the display name (2-120 chars) via a new PATCH route.
- Slug stays immutable to keep dashboard URLs stable.
- Adds updateOrganizationName helper in orgs.ts.
* feat(den-web): rename organization from Members page
- Adds an 'Organization' settings card above the Members tabs with inline
rename for workspace owners.
- Non-owners see a read-only summary explaining who can rename.
- Wires a new updateOrganizationName mutation through OrgDashboardProvider
that calls PATCH /v1/orgs/:orgId.
* fix(den-api): tolerate missing apps/desktop/package.json in Docker build
PR #1476 introduced a build step that reads apps/desktop/package.json to
bake in a default latest-app-version, but packaging/docker/Dockerfile.den
does not ship the Tauri desktop sources. As a result, the den-dev Docker
stack fails to build after the PR landed. Gracefully fall back to 0.0.0
(matching the runtime default) when the file is absent, and allow a
DEN_API_LATEST_APP_VERSION env override so deployers can still pin a
real value.
* docs(den-web): add rename organization screenshots
Captured via Chrome MCP against packaging/docker/den-dev-up.sh:
- before: Members page shows Organization card with Rename button.
- editing: inline form with the current name pre-filled.
- after: new name shown with success state, sidebar also updated.
* refactor(den-web): extract DenCard primitive and drop drop shadows
The dashboard has been inlining the same card style (rounded-[30px] + p-6
+ shadow-[0_18px_48px_-34px_rgba(15,23,42,0.22)]) on every form surface.
Per Den visual language we do not use drop shadows, so the repeated
shadow class is both incorrect and a copy-paste risk.
- Add ee/apps/den-web/app/(den)/_components/ui/card.tsx exporting DenCard
with two size presets (comfortable + spacious). Shadows are explicitly
omitted and the component is designed so they cannot be re-introduced
via className (no tokens ever emit shadow utilities).
- Replace all five inline cards in manage-members-screen.tsx with DenCard.
- Replace the reused sibling card in api-keys-screen.tsx with DenCard.
- Re-capture members-rename screenshots against the refactored UI.
* docs: make start-here app-first
Clarify the primary OpenWork CTA for new users, group self-hosting in one place, and add a missing languages page so localization contributions have a clear home.
* docs: refine get started setup cards
Add an enterprise card beside the cloud entrypoint and remove the self-hosting CTA from the get started page so the setup choices stay focused.
* more clear initial cta
* docs: clarify missing languages contribution path
Reframe the page around the languages OpenWork already ships, then explain where to improve existing locale files and which files need updates to add a new language.
* security: harden release workflows against secret leakage
Verify trusted refs before secret-bearing jobs, narrow secret scope, pin key actions, and remove the opencode agents workflow to reduce workflow attack surface.
* security: drop third-party action pinning
Keep the trusted ref gates and narrower secret exposure, but revert external GitHub Actions back to their tagged versions to avoid broad supply-chain hardening changes in this PR.
* security: scope trusted release refs to dev
Update the workflow trust gates to validate tags and manual refs only against origin/dev, matching this repository's actual protected branch layout.
---------
Co-authored-by: src-opn <src-opn@users.noreply.github.com>
* docs: swap Ollama functional example for Infron LLM gateway
Introduces the LLM gateway concept (single OpenAI-compatible endpoint,
unified billing, fallbacks), replaces the Ollama walkthrough with an
Infron config, and links out to Infron's signup + quickstart per their
reciprocal doc in their OpenWork page.
* docs: frame Infron as hosted gateway vs LiteLLM starting point
Link to Infron's LiteLLM integration page as the canonical open-source
gateway reference, and position Infron as the OpenRouter-style hosted
gateway that sits on top: one key, unified billing, provider fallbacks.
* docs: drop OpenRouter comparison, pitch Infron directly for dev ergonomics
* docs: drop em dashes, loosen Infron pitch to devrel voice
* docs: add Infron model picker + active session screenshots
Introduce a new /integrations route under the org dashboard where users
can simulate connecting GitHub or Bitbucket through a realistic OAuth-
style wizard. The Plugins page now only shows its catalog once at least
one integration is connected; connecting more providers unlocks more
plugins.
- Integrations list card per provider (GitHub, Bitbucket) with connect /
disconnect actions, connected account chips, and repo pills.
- Multi-step connect dialog: authorize -> select account -> select repos
-> connecting -> connected. Dismissable, fully keyboard accessible,
matches the existing OrgLimitDialog scrim/card frame.
- Data layer uses TanStack Query mutations; connections live only in the
React Query cache (in-memory, per user's request). Mutations
invalidate both ['integrations', 'list'] and ['plugins'], so the
Plugins page updates in place when you connect or disconnect.
- plugin-data: each plugin now declares requiresProvider ('any' |
'github' | 'bitbucket'). The plugins queryFn reads the integration
cache and filters accordingly; the catalog stays empty with zero
connections.
- plugins-screen: new 'Connect an integration' empty state with a CTA
that deep-links to /integrations.
- No sidebar entry added (hidden page per request). Header title is
mapped to 'Integrations' so navigating manually still feels coherent.
All data is mocked; the same hook surface (useIntegrations / useConnect
Integration / useDisconnectIntegration / usePlugins) will back a real
API with a one-line queryFn swap later.
Introduce a new /plugins route under the org dashboard that lists plugins
(bundles of skills, hooks, MCP servers, agents, and commands) with a
list view, per-plugin detail view, and tabbed cross-cutting views for
all skills/hooks/MCPs.
- Reuses existing dashboard primitives: DashboardPageTemplate,
UnderlineTabs, DenInput, PaperMeshGradient cards.
- Mirrors the skill-hubs list/detail patterns 1:1 for visual coherence.
- Introduces @tanstack/react-query (scoped to the dashboard subtree)
with a mock queryFn so the data layer can swap to a real API later
with a one-line change.
- Hidden by design: no sidebar nav entry. Reachable only via direct URL
/o/<slug>/dashboard/plugins. Header title is mapped to 'Plugins' so
navigating manually still feels coherent.
* chore(deps): pin opencode CLI and SDK to v1.4.9
- Bump constants.json opencodeVersion v1.2.27 -> v1.4.9 (CI source of
truth consumed by ci-tests, build-desktop, alpha/prerelease/release
workflows, and opencode-agents).
- Bump @opencode-ai/sdk across app, story-book, orchestrator,
opencode-router, server-v2, and refresh the lockfile so all workspaces
resolve to 1.4.9.
* refactor(app): adapt to @opencode-ai/sdk 1.4.9 type changes
- Move Model.reasoning reads to Model.capabilities.reasoning in
model-config.ts and model-behavior.ts (SDK flattened capabilities).
- Simplify utils/providers.ts to a pass-through; Provider now carries
source/options and Model.cost reshapes to {input, output, cache,
experimentalOver200K}, which the mapper no longer needs to translate.
- Cast session.todo() result to TodoItem[] (SDK Todo has no id).
- Update server-v2 test fixtures from 1.2.27 to 1.4.9.
The skill-destination modal shown when importing a shared skill rendered
raw translation keys (e.g. 'share_skill_destination.add_to_workspace')
for five strings in English and French. Those entries were stubbed with
their own keys as values in a previous i18n cleanup and never replaced
with real copy.
Restore proper English copy (reusing the wording already present for the
sibling '_desc' / 'confirm_button' / 'confirm_busy' keys that these
hint/CTA keys supersede) and mirror it in French. Other locales already
had real translations for these keys and are unaffected.
* docs: rewrite intro with privacy-first positioning
Lead with "privacy-first, open-source alternative to Claude Cowork" and
cut the coding-agent framing. Reorganize the page into three scannable
sections (Start / For teams / For developers), keep the existing
self-host/orchestrator steps under a dedicated section below.
* docs: regroup sidebar into outcome-based clusters
Rename tabs "Cloud docs" → "Cloud" and "Cloud API" → "API" for shorter,
clearer labels.
Replace the generic "Desktop App" and "Tutorials" groups in Start here
with two outcome-based clusters: "Connect your stack" (providers, MCPs,
search) and "Do work with it" (browser, automations, skills, sharing).
Reorganize the flat Cloud list into three clusters that map to real
admin questions: "Share with your team" (templates, skill hubs,
providers), "Run in the cloud" (shared workspaces, Slack), and
"Manage access" (members & RBAC). Enterprise stays at the tail as
a standalone contact-sales page.
Slack moves from Start here to Cloud "Run in the cloud" since the
Slack setup doc itself recommends pairing Slack with a remote
workspace.
* docs: surface changelog and roadmap on the intro
Add a one-liner in the developers section pointing to the changelog
and roadmap, and include both in the footer links. Developers
evaluating the project want to see shipping velocity and direction.
* docs(self-host): add dedicated self-host page with cloud/enterprise upsells
Extract the openwork-orchestrator install steps out of the intro into
a dedicated Self-host page. Keeps the intro short and gives
self-hosters a direct, linkable entry point.
The page includes two upsell paths:
- Cloud, for readers who realize mid-read they don't want to run
infra. Links into the team primitives (skill hubs, providers, RBAC,
shared workspaces) that are hardest to replicate on your own box.
- Enterprise, framed around concrete scale pressures (SSO, audit,
allowlists, VPC, support) rather than a generic 'talk to sales'
pitch. Links to the existing cloud-enterprise contact page.
Add the page to the Start here tab as a top-level sibling of the
intro so self-hosters find it immediately.
* docs: move self-host below the outcome clusters
Self-hosting is what people reach for after they've installed the
desktop app and tried the basic flow, not before. Move it below
"Connect your stack" and "Do work with it" so the sidebar reflects
that progression.
* docs: rename intro page title to "Introduction"
"OpenWork" as a sidebar label is tautological — every page is about
OpenWork. "Introduction" tells the reader what the page is, which is
what a sidebar label is for. The in-page hero copy still carries the
positioning.
* docs: rewrite page titles as actions
Sidebar labels should describe what the reader wants to do, not what
the page is. Rename every page title to start with (or imply) a verb:
- Introduction → Get started
- How to connect ChatGPT to Openwork → Connect ChatGPT
- How to get an Anthropic API key → Connect Anthropic
- Adding a custom LLM provider/model → Connect a custom LLM
- Adding a custom MCP → Add an MCP server
- Enable Advanced Search with Exa → Enable Exa search
- Controlling your browser with OpenWork → Control the browser
- Automating Tasks → Automate tasks
- Importing a skill → Import a skill
- How to share your agents with others → Share your setup
- Self-host OpenWork → Self-host
- Missing Documentation? → Report missing docs
Makes the sidebar scannable by intent: each label is a thing the
reader is trying to accomplish.
* docs: restore precision in provider titles
"Connect X" flattened two different setup flows into one label.
Readers scanning the sidebar need to know what they'll do before
clicking:
- Sign in with ChatGPT (OAuth, no key needed)
- Add Anthropic API key (paste a secret from Anthropic)
- Add a custom LLM (config, not auth)
MCP and Exa labels already carry their own distinct verbs and are
left unchanged.
* docs: turn missing-docs into a question with two paths
"Missing docs?" as a question invites the click. Inside, offer both
the low-effort path (email us) and the contributor path (open a PR
against the docs folder). Drops the "A message from the Openwork
Developers" preamble, which was noise.
* docs: reorganize into tab folders, rename files to match titles
Mirrors the tab/group structure in docs.json so files are easier to
locate. Filenames now track page titles (prefixes like how-to- and
cloud- dropped since folders provide that context). Single-page groups
stay flat at the tab root; roadmap and changelog remain at repo root as
their own tabs. Cross-links in mdx files and docs.json redirects
updated for the new paths.
* docs: add roadmap/changelog folders, rename images, deprecate unused assets
Moves roadmap.mdx and changelog.mdx into their own tab folders for
consistency with the rest of the reorg, and removes the orphaned
introduction.mdx. Renames CleanShot/Screenshot/image-* files to
descriptive names based on content and updates the corresponding
alt text. Unused images and a stray .mov land in images/deprecated/
rather than being deleted. docs.json gains /roadmap and /changelog
redirects so old inbound URLs still resolve.
* more clear get starter docs
* docs: render get-started paths as Mintlify cards
* no need to have the same title twice
* edits
* more concise