Scotty 0.5.0 · Released 11 November 2026

Templated blueprints, our own tokens and a shell that pipes.

Scotty 0.5.0 lets you create an app from a blueprint without a compose file. Scotty now issues its own login tokens, so MCP clients can connect, and app:shell takes piped input. Four changes break existing setups, so read the upgrade notes before you roll out.

27commits since 0.4.0
7new features
8bug fixes
4breaking changes
What is new

Highlights of 0.5.0

Three themes run through this release: creating apps from parameters instead of files, a login model that Scotty owns end to end, and a shell you can script.

Templated blueprints

blueprintsapp:createbreaking

A blueprint can now carry its own compose template. It declares parameters as JSON Schema, an allowlist of images and the payload it accepts. Scotty fills in generated values such as secrets and keeps them when the app is re-created. app:create is create-or-update, so CI can run the same command on every pipeline.

# Publish a folder of HTML with the bundled static-html blueprint
scottyctl app:create my-preview --app-blueprint static-html --folder ./site

# Parameters and images come from the blueprint
scottyctl blueprint:info atelier
scottyctl app:create cms-demo --app-blueprint atelier \
  --param ADMIN_PASS=… --image ghcr.io/aincient-labs/atelier-cms:v0.24.0
  • Two blueprints ship with the release: static-html for HTML artifacts and atelier for Atelier CMS.
  • x-scotty-generate creates secrets per app; x-scotty-from fills values such as the domain pattern.
  • A create:<blueprint> permission lets a user create and update apps of that one blueprint, and no others.

Scotty-issued tokens and device login

oauthscottyctlgrantrybreaking

The OIDC provider is used once, at login. After that Scotty issues its own session tokens, verifies the provider's ID token, and stores sessions in SQLite. scottyctl auth:login runs the device grant (RFC 8628) against Scotty's own /device page, so the provider no longer needs the device grant enabled. Logout revokes the session on the server.

scottyctl auth:login    # prints a URL and a code, approve it on /device
scottyctl auth:refresh  # refresh the stored session now
scottyctl auth:logout   # revokes the session on the server

Active sessions are listed on the new Connections page (/connections), where you can revoke them.

Connect Claude through MCP

oauthmcp

Scotty is now an OAuth authorization server for MCP clients such as claude.ai and Claude Code. Clients use the authorization code flow with PKCE and are approved on Scotty's consent page. /mcp only accepts tokens issued for it, with short-lived access tokens and rotating refresh tokens.

ClientHow it logs inToken lifetime
Web UIOIDC login in the browser12 h, no refresh
scottyctlDevice login, approved on /device12 h, refreshed silently, 30-day limit
MCP clientsAuthorization code with PKCE, consent page15 min, rotating refresh, 30-day limit

A shell you can pipe into

app:shell#954breaking

app:shell now separates stdin forwarding from tty allocation, the way docker exec and ssh do. Without a tty the output passes through byte for byte, stderr stays on stderr, and scottyctl exits with the remote exit code. Long-running processes keep streaming output, even when they never read stdin.

# Restore a database dump
scottyctl app:shell my-app db -i -c 'mysql app' < dump.sql

# Stream a dump out of the container
scottyctl app:shell my-app db -c 'mysqldump app | gzip' > dump.sql.gz

# Keep colors and progress bars
scottyctl app:shell my-app web -t -c 'composer install'

Out of search engines

api#962

The Scotty server disallows robots on its own host. When robots are disallowed, stopped apps that fall back to Scotty's landing page are kept out of search indexes too. Robots handling stays on Scotty's own host and does not touch your apps' domains.

Before you upgrade

Four breaking changes

Plan the rollout so that everyone can log in again right after it. Keep the SQLite database on a persistent volume, or sessions are lost on every restart.

Step 1 · Config

Lengthen the JWT secret

api.jwt_secret needs at least 64 bytes. Scotty refuses to start with a shorter one.

Step 2 · Logins

Everyone logs in once

The API rejects provider (GitLab) tokens. Users log in again in the web UI and run scottyctl auth:login. Automation that sent a GitLab token switches to a bearer token.

Step 3 · Roles and scopes

Check roles and re-creates

A role with an unknown or malformed permission now fails the server start instead of being read as *. A re-create cannot move an app to other scopes (403), and replacing an app needs create rights in every one of its scopes. A single * in a payload pattern no longer matches nested paths.

Step 4 · Scripts

Add -t where you need a tty

app:shell --command no longer allocates a remote tty. Scripts that parsed CRLF output or relied on terminal sequences pass -t; remote stderr now goes to local stderr.

Bug fixes

Smaller things that work better

Most fixes harden the shell session and the new login flow.

Shell

  • No lost output and no leftover processes after a session ends.
  • Client input and output run concurrently.
  • Output keeps flowing while the remote process does not read stdin.

Login and API

  • auth:logout revokes the session on the server.
  • Robots handling is limited to Scotty's own host.
  • Stopped apps stay out of search engines when robots are disallowed.
  • Findings from the OAuth review are addressed.

Build and docs

  • Cargo.lock is in sync with Cargo.toml.
  • The create_app doctest passes requested_by (#939).
  • New docs for Scotty-issued tokens, device login and MCP connections.