MCPcopy
hub / github.com/charmbracelet/soft-serve

github.com/charmbracelet/soft-serve @v0.11.6 sqlite

repository ↗ · DeepWiki ↗ · release v0.11.6 ↗
1,366 symbols 5,234 edges 225 files 977 documented · 72%
README

Soft Serve

<img style="width: 451px" src="https://stuff.charm.sh/soft-serve/soft-serve-header.png?0" alt="A nice rendering of some melting ice cream with the words ‘Charm Soft Serve’ next to it">


<a href="https://github.com/charmbracelet/soft-serve/releases"><img src="https://img.shields.io/github/release/charmbracelet/soft-serve.svg" alt="Latest Release"></a>
<a href="https://pkg.go.dev/github.com/charmbracelet/soft-serve?tab=doc"><img src="https://godoc.org/github.com/golang/gddo?status.svg" alt="GoDoc"></a>
<a href="https://github.com/charmbracelet/soft-serve/actions"><img src="https://github.com/charmbracelet/soft-serve/workflows/build/badge.svg" alt="Build Status"></a>
<a href="https://nightly.link/charmbracelet/soft-serve/workflows/nightly/main"><img src="https://shields.io/badge/-Nightly%20Builds-orange?logo=hackthebox&logoColor=fff&style=appveyor"/></a>

A tasty, self-hostable Git server for the command line. 🍦

Soft Serve screencast

  • Easy to navigate TUI available over SSH
  • Clone repos over SSH, HTTP, or Git protocol
  • Git LFS support with both HTTP and SSH backends
  • Manage repos with SSH
  • Create repos on demand with SSH or git push
  • Browse repos, files and commits with SSH-accessible UI
  • Print files over SSH with or without syntax highlighting and line numbers
  • Easy access control
  • SSH authentication using public keys
  • Allow/disallow anonymous access
  • Add collaborators with SSH public keys
  • Repos can be public or private
  • User access tokens

Where can I see it?

Just run ssh git.charm.sh for an example. You can also try some of the following commands:

# Jump directly to a repo in the TUI
ssh git.charm.sh -t soft-serve

# Print out a directory tree for a repo
ssh git.charm.sh repo tree soft-serve

# Print a specific file
ssh git.charm.sh repo blob soft-serve cmd/soft/main.go

# Print a file with syntax highlighting and line numbers
ssh git.charm.sh repo blob soft-serve cmd/soft/main.go -c -l

Or you can use Soft Serve to browse local repositories using soft browse [directory] or running soft within a Git repository.

Installation

Soft Serve is a single binary called soft. You can get it from a package manager:

# macOS or Linux
brew install charmbracelet/tap/soft-serve

# Windows (with Winget)
winget install charmbracelet.soft-serve

# Arch Linux
pacman -S soft-serve

# Nix
nix-env -iA nixpkgs.soft-serve

# Debian/Ubuntu
sudo mkdir -p /etc/apt/keyrings
curl -fsSL https://repo.charm.sh/apt/gpg.key | sudo gpg --dearmor -o /etc/apt/keyrings/charm.gpg
echo "deb [signed-by=/etc/apt/keyrings/charm.gpg] https://repo.charm.sh/apt/ * *" | sudo tee /etc/apt/sources.list.d/charm.list
sudo apt update && sudo apt install soft-serve

# Fedora/RHEL
echo '[charm]
name=Charm
baseurl=https://repo.charm.sh/yum/
enabled=1
gpgcheck=1
gpgkey=https://repo.charm.sh/yum/gpg.key' | sudo tee /etc/yum.repos.d/charm.repo
sudo yum install soft-serve

You can also download a binary from the releases page. Packages are available in Alpine, Debian, and RPM formats. Binaries are available for Linux, macOS, and Windows.

Or just install it with go:

go install github.com/charmbracelet/soft-serve/cmd/soft@latest

A Docker image is also available.

Setting up a server

Make sure git is installed, then run soft serve. That’s it.

This will create a data directory that will store all the repos, ssh keys, and database.

By default, program configuration is stored within the data directory. But, this can be overridden by setting a custom path to a config file with SOFT_SERVE_CONFIG_LOCATION that is pre-created. If a config file pointed to by SOFT_SERVE_CONFIG_LOCATION, the default location within the data dir is used for generating a default config.

To change the default data path use SOFT_SERVE_DATA_PATH environment variable.

SOFT_SERVE_DATA_PATH=/var/lib/soft-serve soft serve

When you run Soft Serve for the first time, make sure you have the SOFT_SERVE_INITIAL_ADMIN_KEYS environment variable is set to your ssh authorized key. Any added key to this variable will be treated as admin with full privileges.

Using this environment variable, Soft Serve will create a new admin user that has full privileges. You can rename and change the user settings later.

Check out Systemd on how to run Soft Serve as a service using Systemd. Soft Serve packages in our Apt/Yum repositories come with Systemd service units.

Server Configuration

Once you start the server for the first time, the settings will be in config.yaml under your data directory. The default config.yaml is self-explanatory and will look like this:

# Soft Serve Server configurations

# The name of the server.
# This is the name that will be displayed in the UI.
name: "Soft Serve"

# Log format to use. Valid values are "json", "logfmt", and "text".
log_format: "text"

# The SSH server configuration.
ssh:
  # The address on which the SSH server will listen.
  listen_addr: ":23231"

  # The public URL of the SSH server.
  # This is the address that will be used to clone repositories.
  public_url: "ssh://localhost:23231"

  # The path to the SSH server's private key.
  key_path: "ssh/soft_serve_host"

  # The path to the SSH server's client private key.
  # This key will be used to authenticate the server to make git requests to
  # ssh remotes.
  client_key_path: "ssh/soft_serve_client"

  # The maximum number of seconds a connection can take.
  # A value of 0 means no timeout.
  max_timeout: 0

  # The number of seconds a connection can be idle before it is closed.
  idle_timeout: 120

# The Git daemon configuration.
git:
  # The address on which the Git daemon will listen.
  listen_addr: ":9418"

  # The maximum number of seconds a connection can take.
  # A value of 0 means no timeout.
  max_timeout: 0

  # The number of seconds a connection can be idle before it is closed.
  idle_timeout: 3

  # The maximum number of concurrent connections.
  max_connections: 32

# The HTTP server configuration.
http:
  # The address on which the HTTP server will listen.
  listen_addr: ":23232"

  # The path to the TLS private key.
  tls_key_path: ""

  # The path to the TLS certificate.
  tls_cert_path: ""

  # The public URL of the HTTP server.
  # This is the address that will be used to clone repositories.
  # Make sure to use https:// if you are using TLS.
  public_url: "http://localhost:23232"

  # The cross-origin request security options
  cors:
    # The allowed cross-origin headers
    allowed_headers:
      - "Accept"
      - "Accept-Language"
      - "Content-Language"
      - "Content-Type"
      - "Origin"
      - "X-Requested-With"
      - "User-Agent"
      - "Authorization"
      - "Access-Control-Request-Method"
      - "Access-Control-Allow-Origin"

    # The allowed cross-origin URLs
    allowed_origins:
      - "http://localhost:23232" # always allowed
      # - "https://example.com"

    # The allowed cross-origin methods
    allowed_methods:
      - "GET"
      - "HEAD"
      - "POST"
      - "PUT"
      - "OPTIONS"

# The database configuration.
db:
  # The database driver to use.
  # Valid values are "sqlite" and "postgres".
  driver: "sqlite"
  # The database data source name.
  # This is driver specific and can be a file path or connection string.
  # Make sure foreign key support is enabled when using SQLite.
  data_source: "soft-serve.db?_pragma=busy_timeout(5000)&_pragma=foreign_keys(1)"

# Git LFS configuration.
lfs:
  # Enable Git LFS.
  enabled: true
  # Enable Git SSH transfer.
  ssh_enabled: false

# Cron job configuration
jobs:
  mirror_pull: "@every 10m"

# The stats server configuration.
stats:
  # The address on which the stats server will listen.
  listen_addr: ":23233"
# Additional admin keys.
#initial_admin_keys:
#  - "ssh-rsa AAAAB3NzaC1yc2..."

You can also use environment variables, to override these settings. All server settings environment variables start with SOFT_SERVE_ followed by the setting name all in uppercase. Here are some examples:

  • SOFT_SERVE_NAME: The name of the server that will appear in the TUI
  • SOFT_SERVE_SSH_LISTEN_ADDR: SSH listen address
  • SOFT_SERVE_SSH_KEY_PATH: SSH host key-pair path
  • SOFT_SERVE_HTTP_LISTEN_ADDR: HTTP listen address
  • SOFT_SERVE_HTTP_PUBLIC_URL: HTTP public URL used for cloning
  • SOFT_SERVE_GIT_MAX_CONNECTIONS: The number of simultaneous connections to git daemon

Database Configuration

Soft Serve supports both SQLite and Postgres for its database. Like all other Soft Serve settings, you can change the database driver and data source using either config.yaml or environment variables. The default config uses SQLite as the default database driver.

To use Postgres as your database, first create a Soft Serve database:

psql -h<hostname> -p<port> -U<user> -c 'CREATE DATABASE soft_serve'

Then set the database data source to point to your Postgres database. For instance, if you're running Postgres locally, using the default user postgres and using a database name soft_serve, you would have this config in your config file or environment variable:

db:
  driver: "postgres"
  data_source: "postgres://postgres@localhost:5432/soft_serve?sslmode=disable"

Environment variables equivalent:

SOFT_SERVE_DB_DRIVER=postgres \
SOFT_SERVE_DB_DATA_SOURCE="postgres://postgres@localhost:5432/soft_serve?sslmode=disable" \
soft serve

You can specify a database connection password in the data source url. For example, postgres://myuser:dbpass@localhost:5432/my_soft_serve_db.

LFS Configuration

Soft Serve supports both Git LFS HTTP and SSH protocols out of the box, there is no need to do any extra set up.

Use the lfs config section to customize your Git LFS server.

Note: The pure-SSH transfer is disabled by default.

Server Access

Soft Serve at its core manages your server authentication and authorization. Authentication verifies the identity of a user, while authorization determines their access rights to a repository.

To manage the server users, access, and repos, you can use the SSH command line interface.

Try ssh localhost -i ~/.ssh/id_ed25519 -o IdentitiesOnly=yes -p 23231 help for more info. Make sure you use your key here.

Note The IdentitiesOnly option is used to prevent SSH from using any other keys in your ~/.ssh directory. This is useful when you have multiple keys, and you want to use a specific key for Soft Serve.

For ease of use, instead of specifying the key, port, and hostname every time you SSH into Soft Serve, add your own Soft Serve instance entry to your SSH config. For instance, to use ssh soft instead of typing ssh localhost -i ~/.ssh/id_ed25519 -o IdentitiesOnly=yes -p 23231, we can define a soft entry in our SSH config file ~/.ssh/config.

Host soft
  HostName localhost
  Port 23231
  IdentityFile ~/.ssh/id_ed25519
  IdentitiesOnly yes

Now, we can do ssh soft to SSH into Soft Serve. Since git is also aware of this config, you can use soft as the hostname for your clone commands.

git clone ssh://soft/dotfiles
# make changes
# add & commit
git push origin main

Note The -i and -o parts will be omitted in the examples below for brevity. You can add your server settings to your sshconfig for quicker access.

Authentication

Everything that needs authentication is done using SSH. Make sure you have added an entry for your Soft Serve instance in your ~/.ssh/config file.

By default, Soft Serve gives read-only permission to anonymous connections to any of the above protocols. This is controlled by two settings anon-access and allow-keyless.

  • anon-access: Defines the access level for anonymous users. Available options are no-access, read-only, read-write, and admin-access. Default is read-only.
  • allow-keyless: Whether to allow connections that doesn't use keys to pass. Setting this to false would disable access to SSH keyboard-interactive, HTTP, and Git protocol connections. Default is true.
$ ssh -p 23231 localhost settings
Manage server settings

Usage:
  ssh -p 23231 localhost settings [command]

Available Commands:
  allow-keyless Set or get allow keyless access to repositories
  anon-access   Set or get the default access level for anonymous users

Flags:
  -h, --help   help for settings

Use "ssh -p 23231 localhost settings [command] --help" for more information about a command.

Note These settings can only be changed by admins.

When allow-keyless is disabled, connections that don't use SSH Public Key authentication will get denied. This means cloning repos over HTTP(s) or git:// will get denied.

Meanwhile, anon-access controls the access level granted to connections that use SSH Public Key authentication but are not registered users. The default setting for this is read-only. This will grant anonymous connections that use SSH Public Key authentication read-only access to public repos.

anon-access is also used in combination with `all

Extension points exported contracts — how you extend this code

Object (Interface)
Object is an interface for objects that can be stored. [6 implementers]
pkg/storage/storage.go
IdentifiableItem (Interface)
IdentifiableItem is an item that can be identified by a string. Implements list.DefaultItem. [9 implementers]
pkg/ui/components/selector/selector.go
Client (Interface)
Client is a Git LFS client to communicate with a LFS source API. [3 implementers]
pkg/lfs/client.go
Repository (Interface)
Repository is a Git repository interface. [2 implementers]
pkg/proto/repo.go
LFSStore (Interface)
LFSStore is the interface for the LFS store. [1 implementers]
pkg/store/lfs.go
Runner (Interface)
Runner is a job runner. [1 implementers]
pkg/jobs/jobs.go
Hooks (Interface)
Hooks provides an interface for git server-side hooks. [1 implementers]
pkg/hooks/hooks.go
EventPayload (Interface)
EventPayload is a webhook event payload. [1 implementers]
pkg/webhook/common.go

Core symbols most depended-on inside this repo

Error
called by 137
pkg/cron/cron.go
WrapError
called by 121
pkg/db/errors.go
Context
called by 91
pkg/ui/common/common.go
Rebind
called by 86
pkg/db/handler.go
Name
called by 77
pkg/proto/repo.go
ID
called by 71
pkg/proto/user.go
renderJSON
called by 69
pkg/web/git_lfs.go
FromContext
called by 67
pkg/backend/context.go

Shape

Method 754
Function 397
Struct 152
TypeAlias 35
Interface 23
FuncType 5

Languages

Go100%

Modules by API surface

pkg/ui/components/selector/selector.go35 symbols
pkg/backend/repo.go32 symbols
pkg/config/config.go29 symbols
pkg/ui/pages/repo/log.go28 symbols
pkg/web/git.go27 symbols
pkg/ui/pages/repo/repo.go26 symbols
pkg/ui/pages/repo/files.go24 symbols
pkg/backend/user.go22 symbols
testscript/script_test.go21 symbols
pkg/git/lfs.go21 symbols
pkg/db/logger.go21 symbols
cmd/soft/browse/browse.go20 symbols

Dependencies from manifests, versioned

charm.land/bubbles/v2v2.0.0 · 1×
charm.land/bubbletea/v2v2.0.2 · 1×
charm.land/glamour/v2v2.0.0 · 1×
charm.land/lipgloss/v2v2.0.2 · 1×
charm.land/log/v2v2.0.0 · 1×
charm.land/wish/v2v2.0.0 · 1×
github.com/alecthomas/chroma/v2v2.23.1 · 1×
github.com/anmitsu/go-shlexv0.0.0-2020051411343 · 1×
github.com/atotto/clipboardv0.1.4 · 1×
github.com/aymanbagabas/git-modulev1.8.4-0.20250826192 · 1×
github.com/aymerick/douceurv0.2.0 · 1×
github.com/beorn7/perksv1.0.1 · 1×

Datastores touched

postgresDatabase · 1 repos
soft_serveDatabase · 1 repos

For agents

$ claude mcp add soft-serve \
  -- python -m otcore.mcp_server <graph>

⬇ download graph artifact