GemDB Code installs GemDB, an object database, and lets you work with it using Python in VS Code. Unlike a SQL database, there are no tables to design and no SQL to write: your Python objects are stored as they are, and every commit is an ACID (atomic, consistent, isolated, durable) transaction. Create objects, commit transactions, and explore your data without leaving your editor. The guided walkthrough takes you from install to your first commit.
GemDB Code is in beta and is not intended for production use.
GemDB Code runs one GemDB database under ~/GemDB, with no server to install and no credentials to
manage. After the setup finishes, you can start testing out the GemDB Shell or a GemDB Notebook, or
move on and explore the Brain Freeze demo.
GemDB Code runs on macOS with Apple Silicon and on Linux (x86-64 or ARM64) and needs VS Code 1.101 or later. For a complete list, see Requirements.
-
Install GemDB Code. In the Extensions view, search for
GemDB Codeand click Install. VS Code shows a dialog about the publisher, GemDB, which it marks as not verified. Choose Trust Publisher & Install. Setup then starts on its own. -
Let initial setup finish. Progress appears in notifications at the bottom right of VS Code. If you miss one, click the bell icon in the status bar. If the operating system needs a setting changed, follow the prompts. For more information, see Setup and permissions.
-
Open the GemDB Code sidebar. For more information, see The GemDB Code sidebar.
-
Follow the walkthrough. VS Code opens Get Started with GemDB Code the first time you install GemDB Code. It takes you through setup, the GemDB Shell, a notebook, exploring a real application, and stopping the database. To open it again, see The guided walkthrough.
-
Try the Brain Freeze demo. You are ready to explore a working application. When VS Code prompts you to trust the folder, choose to trust it, so Python can run there. For more information, see Trust
~/GemDB. To get started, click The Brain Freeze demo.
The GemDB Shell is a Python shell (a REPL, or read-eval-print loop) that runs inside the database. For more information, see Python in the database.
GemDB Code comes with a ready-made GemDB Notebook, with an example that shows GemDB in action. The Python kernel is built into the extension, so you do not need the Jupyter extension or a local Python install.
Click New GemDB Notebook (the notebook icon) at the top of the GemDB Code sidebar to open a notebook with a starter cell, ready to run.
# Python here runs inside your GemDB database.
# Everything reachable from gemdb.root is still there tomorrow.
import gemdb
gemdb.root["greeting"] = "Hello from GemDB!"
gemdb.commit()
gemdb.root["greeting"]Running the cell shows 'Hello from GemDB!'. For more information, see Notebooks.
GemDB Code includes an MCP (Model Context Protocol) server, so AI agents such as Claude Code or Cursor can explore your data, run Python in your database, and commit changes. For more information, see Connect an AI agent.
An AI agent does not know how GemDB stores data unless you tell it. Paste this into your agent's chat before you ask it to build or change an application, and replace the last line with what you want:
Read https://raw.githubusercontent.com/GemTalk/GemDB_Code/main/README.md before you write any code,
starting with the sections "Python in the database", "The `gemdb` command" and "Build an application
on GemDB". Then follow these rules:
- Keep the application's data in Python objects under `gemdb.root`, and call
`gemdb.commit()` when a change is complete. There is no ORM or serialization step.
- Run the program with `gemdb`, for example `gemdb main.py`, not with `python3`.
- Give the application its own namespace. At the top level of the entry file, right after
`import gemdb`, call `gemdb.use_namespace("<short app name>")`, and only then import the
application's modules. Do not call it inside a function.
- Run the application from one entry file, such as `main.py`. A namespace accepts only one, so a
second script, such as a test or admin file, fails. If the program has several tasks, choose the
task with a command-line argument, in the form `gemdb main.py <task> [arguments]`.
- To look at the application's data through the MCP server or the GemDB Shell, call
`gemdb.use_namespace("<short app name>")` first.
My application: <describe what you want it to do>
The link opens the README as plain Markdown, which agents read more efficiently than the page GitHub renders.
The rest of this page covers the details behind each feature.
- Requirements
- Platform support
- Setup and permissions
- The guided walkthrough
- The GemDB Code sidebar
- Start and stop the database
- Sessions
- Database space and garbage collection
- Python in the database
- The
gemdbcommand - Build an application on GemDB
- Notebooks
- Connect an AI agent
- The Brain Freeze demo
- Where things live
- GemDB Code updates and associated data
- Settings
- Commands
- Using GemDB Code vs. GemStone/S
- Uninstall GemDB Code
- Privacy
- License
GemDB Code is available from the VS Code Marketplace and, for VSCodium and other compatible editors, from Open VSX.
You need:
- VS Code 1.101 or later. On a Mac, use the Apple Silicon build. On Linux, install VS Code from
code.visualstudio.com (the
.debor.rpmpackage), not as a Snap, which is what Ubuntu's App Center installs. A Snap runs VS Code on an older copy of the system libraries than the database engine needs, so notebooks and the GemDB Shell cannot connect. - A supported platform (see Platform support). On Linux, a glibc-based distribution; musl-based distributions such as Alpine are not supported.
- Permission to use
sudoonce if the operating system's shared-memory limit is below 1 GB. This is common on macOS and rare on Linux. The database does not start until the limit is raised. On Linux,sudois also needed for the optionalRemoveIPC=nosetting (see Changes that need your permission). - Internet access to
dl.gemdb.comfor the one-time engine download. - About 11 GB of free disk space on macOS, or about 12 GB on Linux, under
~/GemDB, on a local disk. The database reserves its full 10 GB limit when it first starts, so your data does not need extra room. If your home directory is on a Network File System (NFS) mount, as it is on many shared Linux machines, see Where things live. - At least 500 MB of free memory, and more as your data and the number of open notebooks grow.
- On Linux,
unzip. Most distributions include it; if yours does not, install it with your package manager (for example,sudo apt install unzip).
Needed only for some features:
git, for Install Brain Freeze Demo.- An MCP client that supports the Streamable HTTP transport, and a free port on
127.0.0.1(50390by default), for connecting an AI agent.
You do not need:
- A local Python installation. All Python runs inside the database, on the Python implementation that ships with the extension. GemDB Code never uses a Python installed on your machine.
- The Jupyter or Python extensions, or
ipykernel. GemDB Notebooks use VS Code's built-in notebook support, so leave the built-in Jupyter Notebook support extension enabled. VS Code may offer to install Microsoft's Python extension when you open a notebook or Python file; GemDB Code does not need it. - Node.js. The
gemdbcommand runs on VS Code's own runtime. pipor a virtual environment. There is no package installation step. When you rungemdb main.py,main.pycan import any other.pyfile in its folder, such asfrom tasks import TaskList, without changingsys.path.
| Platform | Status |
|---|---|
| macOS, Apple Silicon | Supported |
| Linux, x86-64 | Supported |
| Linux, ARM64 | Supported |
| macOS, Intel | Not supported |
| Windows | Not supported |
GemDB Code ships its Python runtime with a native library built for each platform's database engine, so the extension is published per platform, and every supported platform is built and tested on its own architecture. On an unsupported platform, the Marketplace still lists GemDB Code but marks it as not available for that platform, and you cannot install it.
In a local VS Code window, setup starts on its own the first time the extension activates on a
machine. GemDB Code downloads the database engine (about 170 MB on macOS, about 470 MB on Linux) and
creates one database under ~/GemDB. In a remote window (SSH, WSL, dev containers), or after you
cancel setup, click Set Up GemDB in the GemDB Code sidebar, or run GemDB: Set Up GemDB from
the Command Palette.
You can cancel the download. Canceling keeps what has already been downloaded, and Set Up GemDB picks up from there.
The first time the database starts, usually right after setup, GemDB Code installs Python support into it. This takes a few minutes and shows its progress in a notification. If the database cannot start yet, this happens the first time you open a shell or run a notebook cell instead.
When a GemDB Code update ships newer Python support, GemDB Code prompts you before installing it into a database that already has Python support. Data committed with the old version stops working as its type afterward (dates and times, decimals, tuples and sets, and instances of your classes), so install it into a database that holds nothing you need. If you keep the current version, GemDB Code does not prompt you again for that update; GemDB: Reinstall the Python Execution Engine installs it later.
GemDB Code automates what is inert and reversible: files under ~/GemDB, starting the database
(shown in the GemDB Code sidebar and the status bar, and stopped with one click), and adding gemdb
to VS Code's terminals (removed when you disable the extension). For anything persistent or
machine-wide, it prompts you and waits for your permission:
- Raising shared memory needs
sudoand changes the machine for all software. GemDB Code checks whether the operating system's shared-memory limit is at least 1 GB when setup starts, while the engine downloads, and again each time the database starts. If the shared-memory setting is insufficient, GemDB Code prompts you for permission to raise the limit. This is often needed on macOS; most Linux systems already allow enough. When you choose Configure, GemDB Code opens a terminal where you type your password yourself. After the script runs, GemDB Code checks again. If shared memory is still below 1 GB, it shows an error and the database does not start. If you choose Cancel, the database cannot start, and the Shared memory row in the GemDB Code sidebar shows that the database cannot start until it has more shared memory. To address this requirement, start the database again, click that row, or run GemDB: Configure Shared Memory from the Command Palette. - On Linux, keeping the database running after you log out needs systemd's
RemoveIPC=no, which also needssudo. This change is recommended but not required: the database starts without it. If the shared-memory dialog appears, it lists this change as recommended, and GemDB Code runs it in its own terminal. Otherwise, click the Survives logout row in the GemDB Code sidebar, or run GemDB: Keep the Database Running After Logout from the Command Palette. The change takes effect at once. If systemd cannot load it straight away, the row stays and reads not yet applied until you restart your computer.
GemDB Code never edits your shell profile. For the line to add to it, see
The gemdb command.
AI client configuration is different: GemDB Code sets it up for you where it can, so each client
connects to the right MCP server. In VS Code, it registers the server automatically. For Claude
Code, it runs Claude Code's own claude mcp add command for the open folder and shows you how to
undo it. For Claude Desktop and Cursor, it copies a JSON snippet with the server's address for you
to merge into that client's configuration file. See
Connect an AI agent.
GemDB Code installs the Brain Freeze demo and its other folders under ~/GemDB, and VS Code opens
any folder you have not trusted in Restricted Mode. So by default, GemDB Code's folders open in
Restricted Mode. There, you can use the GemDB Code sidebar and start or stop the database, but you
cannot run Python: notebook cells, Run Python File in GemDB, Debug Python File in GemDB,
and the GemDB Shell all wait until
you trust the folder, and connecting Claude Code needs a trusted folder too.
To work with GemDB Code, trust ~/GemDB once: run Workspaces: Manage Workspace Trust from the
Command Palette and add ~/GemDB to your trusted folders. VS Code also trusts its subfolders, so
the Brain Freeze demo and anything else GemDB Code installs there are covered, and no other folder
is affected. If you have not done this yet, VS Code prompts you the first time you run Python in one
of these folders. Choose Trust Folder & Continue to trust that folder.
The walkthrough, Get Started with GemDB Code, takes you through setup, the GemDB Shell, a notebook, exploring a real application, and stopping the database. VS Code opens it automatically only the first time you install GemDB Code. To open it again:
- Open the Command Palette (Ctrl+Shift+P, or Cmd+Shift+P on macOS), type
Open Walkthrough, and choose Welcome: Open Walkthrough.... - From the list, choose Get Started with GemDB Code. It is labeled GemDB Code, and you can
type
GemDBto narrow the list.
Click the GemDB Code icon in the Activity Bar, on the far left of VS Code. The Primary Side Bar
then shows the GemDB view, which this page calls the GemDB Code sidebar. Its rows show whether
the database is Running or Stopped, the database engine version, the database, how much of
its space is used (Space), whether it is recording statistics (Statistics), Python support,
AI agent access, and shared memory. Click Space to collect garbage now, as described in
Database space and garbage collection. Click
Statistics to open the newest statistics file in GemDB Stats, GemTalk's statistics viewer. The
database records its statistics every 20 seconds to ~/GemDB/db/stat, one file a day, and deletes
files after 14 days.
On Linux, a Survives logout row appears when RemoveIPC=no is not set. Click it to set it. Once
a notebook in this window has started a session by running a cell, a Sessions row also appears;
if you do not see it, click Refresh (↻). See Sessions.
The buttons along the top of the sidebar are:
- Start GemDB (▷) or Stop GemDB (■), depending on whether the database is running
- Open GemDB Shell (
>_) and New GemDB Notebook (the notebook icon) - Refresh
- ⋯, a menu with everything else, including Connect an AI Agent to GemDB and Uninstall GemDB
The commands are also in the Command Palette (Ctrl+Shift+P, or Cmd+Shift+P on macOS), where each
name starts with GemDB:. Type GemDB there to list them. This page gives each command's sidebar
label, and uses the GemDB: form for commands that are only in the Command Palette.
While the database is running, the status bar at the bottom of the window also shows GemDB, and clicking it stops the database.
The database keeps running in the background after you close VS Code, so your data stays available to scripts, terminals, and agents. When the extension activates, GemDB Code starts the database if it is set up and you have not stopped it yourself, so your first notebook cell does not have to wait. Running Python also starts the database if it is not running.
If you stop the database yourself, with the Stop GemDB button in the GemDB Code sidebar or the
status bar, it stays stopped until something needs it again: you start it, you run Python in VS Code
or with the gemdb command, or an agent inside VS Code uses the MCP server. A database that stopped
for any other reason, such as a reboot, starts again the next time the extension activates.
When you stop the database, GemDB Code closes the sessions this window holds (its notebooks) and stops the MCP server. Anything those sessions have not committed is lost, so commit before you stop. If another session is still logged in, such as a GemDB Shell or a notebook in another window, GemDB Code prompts you for approval before disconnecting it.
A session is one logged-in connection to the database, with its own uncommitted changes. The
database that GemDB Code installs allows 10 sessions at once, and the database's own background
processes use some of them. Each GemDB Shell, each notebook that has run a cell, each running
gemdb script, and each connected AI agent uses one session. GemDB Code itself holds one, and so
does the MCP server while it runs.
If you run out of sessions, GemDB Code shows an error that names the session in this window that has been idle longest. Close a notebook or a GemDB Shell to free one. Once a notebook in this window has run a cell, click Refresh (↻) at the top of the GemDB Code sidebar to see a Sessions row. It shows how many sessions this window holds, and hovering over it lists each notebook and how long it has been idle.
GemDB Code refreshes a session that has been idle for 10 minutes and has no uncommitted changes, so the session does not hold back garbage collection. It never changes a session that has uncommitted changes. To stop a session you do not need, choose Stop a Database Session… from the sidebar's ⋯ menu. It lists every session, with the ones holding back garbage collection first, and stops the one you pick after you confirm. Anything that session had not committed is lost.
The database that GemDB Code installs is limited to 10 GB by the license that comes with it. It
reserves all 10 GB on disk when it first starts. The Space row in the GemDB Code sidebar shows
how much of that space your data uses. When your code stops using an object, the database keeps the
object until a collection removes it; this unused data is garbage. GemDB Code collects garbage on
a schedule, and again whenever less than 2 GB is left. To collect now, click the Space row, or
choose Collect Garbage Now from the sidebar's ⋯ menu. You cannot start a collection from
Python. In a script, a notebook cell or the GemDB Shell, gemdb.admin.garbage_collect() raises a
security error, because Python runs as a database account that does not have that privilege. Use
Collect Garbage Now instead. A collection can take from about a minute to several minutes, and
objects you just removed may need more than one collection before they are gone.
If the database runs out of the space it keeps free, GemDB Code warns you at once. After about three minutes, the database starts stopping sessions that hold back its space, and what they have not committed is lost. Commit your work when you see the warning.
Your code does not talk to the database over a connection: its objects are the database's objects.
Put dicts, lists, or instances of your classes under gemdb.root and commit. They are stored as
they are, and they persist across sessions and restarts. There is no object-relational mapper (ORM),
mapping layer, or serialization step between your code and the database. Every commit is an ACID
transaction, and each shell, notebook, and agent works in its own consistent view of the data.
Python runs inside the database on Grail, GemTalk Systems' implementation of Python for GemDB.
Python in the database matches CPython 3.14. Most of the standard library works, and sqlite3 is
not available. Grail's documentation lists what is supported:
standard library coverage and
popular packages.
For example, a short session in the GemDB Shell looks like this:
GemDB Shell — Python inside the database. This terminal is its own session.
Ctrl+C interrupts · exit() or Ctrl+D leaves
>>> import gemdb
>>> gemdb.root["customers"] = [{"name": "Ada", "orders": [1042, 1043]}]
>>> gemdb.commit()
>>> gemdb.root["customers"][0]["name"]
'Ada'Close the shell, open a new one, and gemdb.root["customers"] is still there. The same code works
in a GemDB Notebook cell, or in a file you run with gemdb <your-file>.py in a VS Code terminal.
Plain python3 cannot import gemdb, because the module lives inside the database.
| Call | What it does |
|---|---|
gemdb.root |
The persistent root, a dict |
gemdb.commit() |
Makes this session's changes permanent; raises ConflictError if another session got there first |
gemdb.abort() |
Discards this session's uncommitted changes |
gemdb.refresh() |
Takes a fresh view to see other sessions' commits; raises PendingChangesError if you have uncommitted changes |
gemdb.needs_commit() |
Whether this session has changes that a commit would write |
gemdb.transaction() |
A with block that commits when it finishes and aborts on an exception |
import gemdb
with gemdb.transaction():
gemdb.root["visits"] = gemdb.root.get("visits", 0) + 1gemdb.transaction() raises an error instead of starting if the session already has uncommitted
changes. Commit or abort them first.
Each session sees other sessions' commits after its own refresh(), abort() or commit().
Setup writes a shell command to ~/GemDB/bin/gemdb that behaves like CPython's command line, backed
by the database:
gemdb hello.py # like python3 hello.py
gemdb -c 'print(1+1)' # like python3 -c
gemdb -m some.module # runs a module
gemdb # the GemDB ShellTerminals you open in VS Code already have gemdb on their PATH. GemDB Code removes it again if you
disable the extension. To use gemdb in terminals outside VS Code, add this line to your shell
profile (adjust the path if you changed gemdb.rootPath):
export PATH="$HOME/GemDB/bin:$PATH"The command needs no environment setup, and it starts the database if the database is not running.
Exit codes work the way scripts expect: 0 on success, 1 on an uncaught exception (Python's traceback
prints), 2 for a missing file, 130 when you stop the script with Ctrl+C (only KeyboardInterrupt
prints), and sys.exit() behaves as in CPython.
input() works in scripts, the GemDB Shell, and notebooks. A script reads stdin, and the GemDB
Shell reads its own prompt line, where Ctrl+C raises KeyboardInterrupt and Ctrl+D raises
EOFError. print() streams, so output appears while the code is still running.
With no arguments, gemdb opens the GemDB Shell, the same program that the Open GemDB Shell
button opens in a terminal. Each shell is a separate session. Use exit() or Ctrl+D to leave.
To run the Python file in the active editor, use the Run button's menu (▷ with an arrow) at the top right of the editor, or GemDB: Run Python File in GemDB in the Command Palette.
To debug it, choose Debug Python File in GemDB from the same menu. The file runs as __main__
in a session of its own, with its output in a GemDB Debug terminal, and breakpoint() opens
Run and Debug on the file just as it does on a notebook cell: the call stack, each frame's locals,
the file's globals, Add to Persisted Objects… and Add Stack to Persisted Objects…. The
session lasts as long as the terminal, so Commit and Abort in Persisted Objects work after
the run ends; closing the terminal ends the session and discards what it did not commit. Ctrl+C in
the terminal stops the run.
Red dots work in .py files: click in the gutter beside a line, and a run that reaches it pauses
there and opens Run and Debug, the same as breakpoint(). That holds for Debug Python File and for a
notebook cell that calls into a .py module. A dot also works in a module the run imports, and one
added while paused stops the run later on. Not supported yet: dots with a condition, hit count or
log message (they never stop the run, and the debugger says so), dots in notebook cells, and dots
in a class defined inside a function. A line that only returns a name, like return x, has no
code to stop at, so its dot stays hollow. A dot on the first line of a for loop's body also stops
once just before the loop's first pass. Run Python File in GemDB has no debugger, so it runs straight
past them.
A GemDB application is a Python program that you run with gemdb. Keep your objects under
gemdb.root and commit when a change is complete. This example has two files in one folder.
tasks.py:
from dataclasses import dataclass, field
from datetime import datetime
@dataclass
class Task:
title: str
created: datetime = field(default_factory=datetime.now)
done: bool = False
class TaskList:
def __init__(self):
self.tasks = []
def add(self, title):
self.tasks.append(Task(title))main.py:
import sys
import gemdb
gemdb.use_namespace("todo")
from tasks import TaskList
if "todo" not in gemdb.root:
gemdb.root["todo"] = TaskList()
todo = gemdb.root["todo"]
if len(sys.argv) > 1:
todo.add(sys.argv[1])
gemdb.commit()
for task in todo.tasks:
print(task.title, task.created.strftime("%Y-%m-%d"))Run gemdb main.py "buy milk", then gemdb main.py "call James". The second run lists both tasks.
- Arguments arrive in
sys.argv, as they do withpython3. - Imports work for any
.pyfile in the same folder as the file you run. That folder is already on the import path, sofrom tasks import TaskListneeds no setup. If two programs in one database each have a differenttasks.py, see Modules and namespaces. - Changes to stored objects are picked up by the next
gemdb.commit(). Appending to a stored list needs no assignment back intogemdb.root.gemdb.needs_commit()says whether a commit has anything to write. - Uncommitted changes are lost. A program that ends without calling
gemdb.commit()orgemdb.abort()discards what it changed. - A stored object keeps its class in the database. When you edit a class and run your program, the edited file updates the class stored under the same module name, and objects you stored earlier use the new methods. The update lasts only if the program commits. Without a commit, the new code applies only while the program runs.
- An object keeps the attribute values it was saved with.
__init__runs once, when you create the object. An attribute you add to__init__later is missing from objects you stored before. Give it a default on the class (done = False) instead. An object without the attribute reads the class value, as in Python, and assigning to it gives that object its own value. - Two sessions that change the same object conflict. The second
gemdb.commit()raisesgemdb.ConflictError, and its message says thatgemdb.abort()discards your changes. To retry, put the change in awith gemdb.transaction():block, which discards a failed attempt:
for attempt in range(5):
try:
with gemdb.transaction():
gemdb.root["todo"].add("buy milk")
break
except gemdb.ConflictError:
passGive each application its own namespace. Without a namespace, GemDB treats a module name as
belonging to the whole database. If you have two programs, each with a file named tasks.py, the
second program's import tasks raises ImportError, because the database already holds a different
module named tasks. A namespace gives each application its own modules and its own gemdb.root,
so two files named tasks.py do not conflict with each other, and an application in one namespace
does not see the data of another. This includes data your application stored before you added a
namespace: it stays in the default root, and the namespace starts empty.
Import gemdb, call gemdb.use_namespace("my-app"), and only then import your modules,
including tasks:
import gemdb
gemdb.use_namespace("my-app")
from tasks import TaskListCall it at the top level of the entry file, not inside a function, where it raises an error.
The name can be any text that is not empty, and capitals matter: my-app and My-App are different
namespaces.
In Python you can run any file at any time. GemDB saves your modules in the database and keeps track
of them by name. It also associates each namespace with the entry file you run. In gemdb main.py,
main.py is the entry file, and the files it imports, such as tasks.py, are its modules. If you
run a different entry file in the same namespace, the second command raises an ImportError that
names __main__. This happens with a second program such as gemdb admin.py, and with a test
script such as gemdb check.py, even if it only reads data. Invoking gemdb -c also causes it,
because it runs your code as a separate file. Editing main.py and running it again works as
expected. Setting the namespace with the GEMDB_NAMESPACE environment variable does not let a
different file run in the same namespace.
Run your application from one entry file, such as main.py, and put everything it does behind that
file. A program that serves requests, such as a web server, already works this way. For a program
with several tasks, choose the task with a command-line argument. For example, a main.py that
reads sys.argv[1] as the task name could take these two commands:
gemdb main.py add "buy milk"
gemdb main.py listTo look at the namespace's data from the GemDB Shell or through the MCP server, call
gemdb.use_namespace("my-app") first.
GemDB Notebooks are ordinary .ipynb files. A notebook you create with New GemDB Notebook uses
the GemDB (Python in the database) kernel automatically. To run another .ipynb file in the
database, select that kernel from the kernel picker at the top right.
- Variables are shared between the cells of a notebook. Running GemDB: Clear Notebook Variables
from the Command Palette clears them without restarting the database. Uncommitted changes stay in
the notebook's session; run
gemdb.abort()to discard those too. print()output streams into the cell while the cell runs.input()opens an input box, and pressing Escape raisesKeyboardInterrupt.breakpoint()pauses the cell and opens VS Code's debugger on it, with no setup: the Call Stack shows the Python frames, the paused line is highlighted, and Variables shows each frame's locals and the notebook's globals, expandable into attributes, items and entries, with classes and functions folded into their own rows. Each value starts with its type, and a container's with its size too ({Point} Point(3, 4),{list: 3} […]); Copy Value copies the value without them. An object with attributes, its own or its class's, opens on everything it has: its own attributes, its class's, its properties and slots, with its methods under function variables and its names with double underscores, such as__module__, under special variables. Right-click a row and choose Set Value to change a local, a global, an attribute, a list item or a dict entry. The value you type is a Python expression, and the run continues with it. It can use the notebook's globals, or a.pyfile's, on any row, and on a Locals row the frame's locals too. Continue resumes the cell where it paused; Stop ends it, along with any cells queued after it. The Debug Console and Watch work at the pause: type Python and it runs in the frame selected in the Call Stack, with that frame's locals, its module's globals and the builtins, and a result opens like a Variables row. Names you bind there last until the run resumes; an error reads as a notebook traceback; a long-running line can be stopped from the notification that appears. A change to an object made there is in the notebook's transaction, as it would be from a cell. Right-click a Variables row for Show in Debug Console, which puts that object in the console (an object with its attributes listed, a list or dict as one row that opens) and leaves its name at the prompt, or_for a nested row, ready for the next line, or Evaluate with self…, which runs an expression withselfbound to it (len(self.history)) and shows the answer there. A line or block pasted with leading spaces, in the console or as a watch, runs as if typed without them. Lines starting with%are GemDB commands, not Python:%persist paddspto Persisted Objects (%persist expr as keyfor anything else),%inspect popensp, or any expression, in an Inspector (below),%pendinglists the persisted objects the notebook's next commit writes — each by its path undergemdb.root, with a link (Ctrl+click) that shows it in Persisted Objects, where each changed object is marked M, its hover sets the committed value beside the new one, and right-click Revert to Committed Value undoes the change —%commitcommits the notebook,%nameslists what you have bound in the console, and%helplists them all. Type%and the console suggests them.gemdbis always available in the console, so a line copied from Persisted Objects, such asgemdb.root["orders"], works even if the program never imported it. What Persisted Objects holds is available by its key too (oforgemdb.root["o"]), unless the paused code has its own nameo;persisted.oreaches it whateveromeans, and a bare persisted name is labeled with where it came from. While you type a name, autocomplete offerspersisted.ofor each persisted entry it starts (press Tab to take a suggestion). Stepping is not supported yet, and neither are red dots in a cell (they work in.pyfiles; see above). Right-click a Variables row and choose Add to Persisted Objects… to keep that object: it goes ingemdb.rootunder the key you give (one is suggested) and is written at the notebook's next commit. The Persisted Objects view, under GemDB and in Run and Debug, lists whatgemdb.rootholds. Each entry opens like a Variables row, with its type badges and groups, and you can keep opening what is inside it, with nothing paused: a committed entry is read by GemDB's own session, any time, even after a restart; one added and not committed yet is read by its notebook's, while that notebook is not running a cell. A list or dict longer than 500 items opens to ranges of 500 —[0 … 499],[500 … 999], … — each opening to its items, nested for a very long one, as in Variables; and whengemdb.rootholds more than 200 entries, it shows them as ranges of 200. Right-click a list, set or dict (or one of its ranges) and choose Go to Item… to type a position (negative counts from the end;[42], as the ranges write it, also works) or a dict's key, and the view opens down to that item and selects it; a key it can't find says so and how keys are written. Every notebook with uncommitted changes is listed belowgemdb.root, paused or not, with Commit and Abort on its row and a Pending changes group: the persisted objects its next commit changes, as%pendinglists them. Click one to go to it undergemdb.root, marked M. The view's title bar always has Commit and Abort for the notebook you are working in. Add Stack to Persisted Objects… on the Call Stack saves the whole paused stack the same way; once committed, Persisted Objects reopens it in the debugger, even after a restart. Its Debug Console works on the saved objects: call a method, bind a name, change an object,%persistone. A change waits uncommitted; the console says when the stack opens that%commit(or ✓) would write it into the saved stack, and closing the stack prompts you to commit or discard what is pending. Debug Python File in GemDB does the same for a.pyfile (see above). In the GemDB Shell and in Run Python File in GemDB,breakpoint()prints where it was and the code carries on.- Inspect, on a Variables row, a Watch row or a Persisted Objects row (or
%inspectin the Debug Console), opens the object in an Inspector beside the editor: a strip of columns, one object each, with tabs for what it has — its Attributes (grouped as in Variables, the groups opening in place), its Items or Entries a page of 100 at a time with a box to jump to a position or a key, its whole Repr (and itsstr()when that differs), its Class (methods by the class that defines them, with their source, the MRO, the bases and the docstring) — and an Evaluate tab that runs Python withselfbound to it and the program's names in scope (Shift+Enter to display the answer; Ctrl+K I opens it in a new column). Double-click a row to open its object in a new column; Enter opens it in place, and ‹ › go back and forward. Each column's header shows the Python that reaches it (p.tags['origin'], which Copy as Expression copies), the object's OOP, and whether it is committed. The Inspector outlives the pause: it holds its objects in the session that has them, so it keeps working after the cell resumes and between cells, and says so when the notebook is busy running one (↻ reads it again). Edit Value… changes a row: what you type runs as an Evaluate line does, and its value is stored in the notebook's transaction, as Set Value stores one; ↺ puts back the very object the row held before. Add to Persisted Objects…, on a row's menu or at the end of a column's tabs, adds that object undergemdb.rootas it does from Variables. An object opened from Persisted Objects' committed entries offers neither, since nothing would commit the change there; open it from a notebook to change it. Evaluate still reads it, and anything an Evaluate line changes there is thrown away. - Each notebook has its own session and its own transaction, so a commit in one notebook never commits another notebook's half-finished changes. Closing a notebook ends its session and discards anything it has not committed.
- A new notebook is untitled until you save it, and saving it for the first time starts a fresh session. Commit before you save, or save before you start work.
- Renaming a notebook from VS Code's Explorer keeps its session and variables. Renaming it outside VS Code, or using Save As, starts a new session.
GemDB Code includes an MCP server, which lets an AI agent such as Claude Code work in your database
on your behalf. Because your data is made of Python objects, the agent works with it by running
Python in the database: for example, to answer a question about your data or to add an attribute to
a class. It can also list what is stored, search for classes and methods, define classes and
methods, and commit changes. The server accepts connections only from programs on your computer
(127.0.0.1), so nothing on your network can reach your database through it.
The MCP server is off by default. Turning it on does not start anything by itself: it sets GemDB Code to run the server whenever the database is running. The server starts when the database starts, and stops when the database stops.
To connect Claude Code:
- Open the folder you want Claude Code to work in, such as the Brain Freeze demo.
- From the GemDB Code sidebar's ⋯ menu, choose Connect an AI Agent to GemDB. The first time, a dialog prompts you to turn the MCP server on. Choose Turn It On. GemDB Code starts the database, and with it the server, if they are not already running.
- From the list of clients, choose Claude Code. GemDB Code runs Claude Code's
claude mcp addcommand for that folder, and then shows you both the command it ran and the command that undoes it. - Start a new Claude Code conversation in that folder: run
claudeagain in a terminal, or start a new conversation in the Claude Code panel. Claude Code reads its list of servers only when a conversation starts, so a conversation that was already open does not see GemDB.
About the Claude Code connection:
-
It applies to that folder only. Claude Code conversations in other folders do not connect to GemDB. This is intentional: each connected conversation uses one of the database's limited sessions (see Sessions).
-
The database must be running. If you stop the database, restart it from the sidebar before you use Claude Code.
-
If you change the server's port (
gemdb.mcp.port), run Connect an AI Agent to GemDB again in that folder. GemDB Code prompts you before it replaces the old entry. -
If GemDB Code cannot run the command, because no folder is open or the
claudecommand cannot be found, it copies the command for you to run from a terminal prompt in that folder. If the folder is not trusted, it shows a warning instead: choose Manage Workspace Trust to trust the folder, then connect again, or choose Copy the Command to run it yourself.claude mcp add --transport http gemdb http://127.0.0.1:50390/mcp
Connecting other AI clients:
- Agents inside VS Code, such as GitHub Copilot in agent mode, need no setup to connect to the MCP server. Once the server is on, it appears in VS Code's MCP server list. If the database is stopped when one of these agents tries to use it, GemDB Code starts it.
- Claude Desktop and Cursor: choose that client in step 3 instead. GemDB Code copies a JSON snippet for you to merge into that client's configuration file. Like Claude Code, these clients need the database to be running.
- Any other MCP client that supports the Streamable HTTP transport: choose Something else to copy the server's URL.
Keep the following in mind:
- Each connected client gets its own session, so agents never see each other's uncommitted work. Agents take sessions from the same limited pool as your notebooks and shells (see Sessions), and the server itself holds one more.
- A client that disconnects badly keeps its session for up to 30 minutes, and reconnecting counts as a new client. An agent that repeatedly crashes and retries can use up every session and leave you unable to log in until those sessions are released. Stopping the database, or choosing Restart the MCP Server from the sidebar's ⋯ menu, releases them immediately. This is why the server is off by default.
- A connected agent can change and commit data, and define code, because running Python in your
database is most of the point. Clicking the Agent write access row in the sidebar, or running
GemDB: Toggle Read-Only Access for AI Agents, logs agents in as a database user that cannot
commit. They can still read everything and run code, but nothing they do is saved. Switching it
restarts the MCP server, which disconnects connected agents, and the first time you turn it on,
GemDB Code adds an
McpReadOnlyuser to your database.
To explore a working application, choose Install Brain Freeze Demo from the ⋯ menu in the
GemDB Code sidebar. It clones brain-freeze, a Flask app
whose data, classes, and views all live in the database, into ~/GemDB/brain-freeze, opens it, and
shows its README. Running it again opens the copy you have rather than replacing it. The command
needs git.
Everything GemDB Code creates is under one directory, ~/GemDB by default (gemdb.rootPath):
| Path | What it is |
|---|---|
db/ |
Your database, the only irreplaceable part |
GemStone64Bit<version>-<platform>/ |
The database engine |
grail/ |
The Python runtime library and native shim |
mcp/ |
The MCP server and the scripts for starting it yourself, created the first time you turn on the MCP server |
bin/ |
The gemdb command |
brain-freeze/ |
The Brain Freeze demo, if you installed it |
locks/, log/, mcp-router.json |
Bookkeeping for the engine and the MCP server |
The directory must be on a local disk. The database engine refuses to open its files on an NFS
mount, so on a machine whose home directories are NFS mounts, ~/GemDB cannot hold the database.
GemDB Code checks before setup downloads anything: if the directory is on NFS, it stops and offers
Choose a Local Folder…, which sets gemdb.rootPath to a GemDB folder inside the one you pick
and sets GemDB Code up there. To choose a location yourself, set gemdb.rootPath in your User
settings before you set up.
Avoid a folder that a sync service such as iCloud Drive, OneDrive, or Dropbox copies, too. That is
why the default is ~/GemDB rather than ~/Documents/GemDB: ~/Documents is commonly synced, and
letting a sync daemon copy a live database out from under the engine corrupts it.
Each GemDB Code release is tied to a database engine version. If a new release also moves to a newer engine version, the database created by the earlier engine version cannot be opened by the newer one. When this happens, GemDB Code shows a message before it starts the database, naming the directory to remove. Removing that directory deletes everything stored in the database.
For this reason, you should not expect to keep access to your data after an update that changes the engine version. VS Code updates extensions automatically, so such an update can arrive without you choosing it. To decide when GemDB Code updates, clear Auto Update on its page in the Extensions view.
Changing the engine version yourself with the gemdb.engineVersion setting has the same effect.
The default GemDB Code settings are designed to work on most systems, so most users do not need to change them. These include settings for locating where GemDB Code stores files, collecting garbage, recording statistics, and setting up the MCP server for AI agents.
If you want to review them, open VS Code's Settings (Ctrl+, on Linux, or Cmd+, on macOS) and search
for gemdb, or go to Extensions > GemDB Code in the list on the left. If you need to
customize your setup, change them in your User settings. They apply to the one GemDB database on
this computer, so a value set in a workspace or folder is ignored, and Settings Sync does not copy
them to other computers. The following table lists all of the settings and the defaults.
| Setting | Default | What it does |
|---|---|---|
gemdb.rootPath |
~/GemDB |
Where GemDB Code keeps everything; must be on a local disk |
gemdb.engineVersion |
(empty) | Advanced: override the pinned engine version |
gemdb.maintenance.garbageCollectionIntervalHours |
24 |
Hours between scheduled garbage collections; 0 collects only when space runs short |
gemdb.maintenance.abortIdleSessionsAfterMinutes |
10 |
Minutes before an idle session with no uncommitted changes is refreshed |
gemdb.statistics.collect |
true |
Whether the database records its statistics for GemDB Stats |
gemdb.statistics.intervalSeconds |
20 |
Seconds between recordings |
gemdb.statistics.keepDays |
14 |
Days before a statistics file is deleted |
gemdb.mcp.enabled |
false |
Run the MCP server, so AI agents can reach your database |
gemdb.mcp.port |
50390 |
The port it listens on, always on 127.0.0.1 |
gemdb.mcp.readOnly |
false |
Log agents in as a database user that cannot commit |
gemdb.externalDatabase.gemstone |
(empty) | Advanced: use a database someone else runs, whose engine is here |
gemdb.externalDatabase.globalDirectory |
/opt/gemstone |
That database's lock directory (GEMSTONE_GLOBAL_DIR) |
gemdb.externalDatabase.stone |
gs64stone |
Its stone |
gemdb.externalDatabase.netldi |
gs64ldi |
Its NetLDI |
gemdb.externalDatabase.user |
DataCurator |
The account GemDB Code logs in as |
gemdb.externalDatabase.passwordFile |
(empty) | A file holding that account's password |
Before you change the following settings, note these important details:
gemdb.rootPath: GemDB Code does not move anything when you change it. Your existing database stays in the old directory, and the new one starts empty, so stop the database first, then run Set Up GemDB in the sidebar to set up the new location. Changing it also closes every notebook's session.gemdb.engineVersion: a database created by a different engine version cannot be opened. See GemDB Code updates and associated data before you change it.gemdb.statistics.*: changes take effect the next time the database starts.gemdb.mcp.enabled: if you turn it on here rather than with Connect an AI Agent to GemDB, the server starts the next time the database starts or you run Python.gemdb.mcp.port: after changing it, choose Restart the MCP Server from the sidebar's ⋯ menu, and update the URL in any external client you connected.gemdb.mcp.readOnly: changing it restarts the MCP server, which disconnects connected agents.gemdb.externalDatabase.*: for a machine where an administrator runs the database — a hosted or shared server. GemDB Code then installs Python support into your account and connects, and never downloads, creates, starts, stops, or removes the database. See Using a database someone else runs for what the administrator sets up.
GemDB Code includes commands to run useful functions in VS Code. The GemDB Code sidebar presents
most of these, either as a button along its top or in its ⋯ menu. To run a command, either use
the Command Palette (Ctrl+Shift+P, or Cmd+Shift+P on macOS) or run it from the sidebar. In the
Command Palette, type GemDB to list the commands. GemDB: Run Python File in GemDB and GemDB:
Debug Python File in GemDB appear only when a Python file is open, and GemDB: Keep the Database
Running After Logout appears only on Linux. The table below reviews the functions available as
commands or in the sidebar.
| Command Palette | Sidebar | What it does |
|---|---|---|
| GemDB: Start GemDB | ▷ button, or click the Stopped row | Starts the database |
| GemDB: Stop GemDB | ■ button | Stops the database (clicking GemDB in the status bar does the same) |
| GemDB: Open GemDB Shell | >_ button, or click the Running row |
Opens a Python shell inside the database |
| GemDB: New GemDB Notebook | Notebook icon button | Opens a notebook with a starter cell |
| GemDB: Refresh Status | ↻ button | Re-reads the state shown in the sidebar |
| GemDB: Connect an AI Agent to GemDB | ⋯ menu, or click the AI agent access row | Turns on the MCP server and connects Claude Code, or gives you another client's configuration |
| GemDB: Show Log | ⋯ menu | Opens GemDB Code's log |
| GemDB: Reinstall the Python Execution Engine | ⋯ menu, or click the Python row when an update is available or the install failed | Reinstalls Python support into your database |
| GemDB: Restart the MCP Server | ⋯ menu, while the database is running | Restarts the MCP server and releases agent sessions |
| GemDB: Collect Garbage Now | ⋯ menu, or click the Space row | Collects the database's garbage immediately |
| GemDB: Stop a Database Session… | ⋯ menu | Lists the sessions on the database and stops the one you pick; anything it had not committed is lost |
| GemDB: Install Brain Freeze Demo | ⋯ menu | Clones the demo application into ~/GemDB/brain-freeze and opens it |
| GemDB: Uninstall GemDB | ⋯ menu | Removes the engine, its Python support, and the MCP server, and offers the option to remove your database |
| GemDB: Set Up GemDB | Set Up GemDB button, before setup has finished | Runs or resumes setup |
| GemDB: Configure Shared Memory | Click the Shared memory row when it needs configuring | Raises the shared-memory limit (prompts you for your password in a terminal) |
| GemDB: Keep the Database Running After Logout | Click the Survives logout row, shown on Linux when RemoveIPC=no is not set |
Sets RemoveIPC=no so the database keeps running after you log out (prompts you for your password in a terminal); Linux only |
| GemDB: Toggle Read-Only Access for AI Agents | Click the Agent write access row, shown when the MCP server is on | Switches whether agents can commit, and restarts the MCP server |
| GemDB: Run Python File in GemDB | None; use the Run button's menu at the top right of a Python file | Runs the current .py file in a terminal; listed only when a Python file is open |
| GemDB: Debug Python File in GemDB | None; use the Run button's menu at the top right of a Python file | Runs the current .py file so that breakpoint() opens the debugger; listed only when a Python file is open |
| GemDB: Clear Notebook Variables | None | Clears the active notebook's variables |
| GemDB: Refresh Notebook View | ↻ button in a GemDB notebook's toolbar | Lets the active notebook see what other sessions have committed: runs gemdb.refresh() in its session |
| GemDB: Open Today's Statistics | Click the Statistics row | Opens the newest statistics file in GemDB Stats |
| GemDB: Open Statistics File… | None | Opens a statistics file you choose in GemDB Stats |
| GemDB: Copy Telemetry ID | None | Copies the ID that identifies your usage data to the clipboard, so you can ask for that data to be found or deleted |
GemDB Code is deliberately small. It manages the database instance that comes with it for demonstration purposes.
If you want to manage a GemStone/S server running your GemStone/S database, use
Jasper: A GemStone Smalltalk IDE.
This full-featured extension exposes the full control surface, including a version picker, a
database list, a login manager, and a process view. GemDB Code and Jasper can be installed side by
side. GemDB Code keeps its files under ~/GemDB and names its processes distinctly, so the
databases remain separately maintained and controlled.
Removing the extension from VS Code does not remove the database or anything under ~/GemDB, and
the database keeps running after VS Code closes. Uninstall in this order:
- Open the GemDB Code sidebar. Click the GemDB Code icon in the Activity Bar, on the far left of VS Code.
- Stop the database. If the top row of the sidebar says Running, click Stop GemDB (■) at the top of the sidebar. Wait until the row says Stopped. GemDB Code does not remove its files while the database is running.
- Remove the database engine and Python support. In the sidebar's ⋯ menu, choose
Uninstall GemDB. The Remove GemDB? dialog shows where your database is and offers:
- Keep my database removes the engine, Python support, and the MCP server. Choose this option
to leave your data in
~/GemDB/db. - Remove everything, including my data also deletes the database. If you choose this option, it cannot be undone.
- Cancel closes the dialog.
- Keep my database removes the engine, Python support, and the MCP server. Choose this option
to leave your data in
- Uninstall the extension. Open the Extensions view, select GemDB Code, and click
Uninstall. Then restart VS Code to finish removing it, as with any extension. After the
restart, the GemDB Code icon is gone from the Activity Bar and
gemdbis no longer on the PATH of VS Code's terminals. - Delete
~/GemDBto remove what is left: thegemdbcommand, logs and bookkeeping files, the Brain Freeze demo and any commits you made in it, and your database if you kept it. The engine's files are read-only, so make them writable first: runchmod -R u+w ~/GemDB, thenrm -rf ~/GemDB.
If you connected an AI agent outside VS Code, remove GemDB Code's entry from that client's
configuration too. For Claude Code, run claude mcp remove gemdb --scope local in the folder where
you connected it.
GemDB Code leaves the operating-system changes you approved during setup in place, because other software may rely on them. To reverse them, delete GemDB Code's files, and then restart your computer.
-
On Linux:
sudo rm -f /etc/sysctl.d/60-gemdb.conf /etc/systemd/logind.conf.d/gemdb.conf
-
On macOS:
sudo launchctl bootout system /Library/LaunchDaemons/com.gemdb.shared-memory.plist 2>/dev/null sudo rm -f /Library/LaunchDaemons/com.gemdb.shared-memory.plist
After the restart, shared memory (and on Linux, RemoveIPC) returns to the system default. Delete
only these files. Files with gemstone or gemtalksystems in their names belong to Jasper, and
while they are present, Jasper's settings stay in effect.
GemDB Code sends usage events that carry no content from your work. The events include a
pseudonymous VS Code machine ID and a coarse location, and VS Code's telemetry.telemetryLevel
setting controls them. See USAGE_DATA.md for exactly what is and is not collected.
MIT. See LICENSE. GemDB Code reuses code from Jasper and bundles Grail and GemTalk's MCP server, all from GemTalk Systems, plus the koffi library. See NOTICE for details. GemDB Code downloads the database engine during setup, and the engine has its own license terms.
To build GemDB Code from source, see CONTRIBUTING.md.
This README ends with a tracking pixel. Read what it does and what it collects.
