This is not an official MongoDB product. There is no support or warranty of any kind, including for any security-related issues, and this software is excluded from the MongoDB Bug Bounty program.
Source Code Algebraic System (SCAS) is a novel approach to programming. Instead of text editing source code files, the programmer applies a series of logical transformations to the codebase. These transformations operate on the entire codebase, and each operation makes all the changes necessary for a single semantic change. Operations move the codebase to a new valid state, and can easily be composed, with higher level operations built up out of lower level ones. Operations can also often be language-agnostic, allowing a level of meta-programming.
This approach is expected to improve coding productivity and accuracy, especially once ML models are layered on top (instead of their current textual approaches). That is, instead of having ML models (such as LLMs) which directly output the modified source code for some desired change, they can instead output the necessary logical transformation operations that are required to achieve the change. This allows the model to operate at a higher level of abstraction, much closer to the planning that is "actual programming", and freeing it from wrangling low level text and syntactic elements.
The general flow is:
-
Parse the codebase and import the syntax tree into MongoDB.
-
Enrich the syntax tree.
-
Apply operation(s) to the enriched syntax tree, regenerating the source code after each.
Development is being done on Ubuntu 22.04, so YMMV in other environments.
-
Python + PyPI packages:
sudo apt-get install python3.10 python3 -m pip install pymongo tree-sitter-language-pack==0.13.0 frozendict httpx==0.28.1 pydantic==2.12.5 -
MongoDB 8.0+ database instance
- https://www.mongodb.com/docs/manual/installation/
- A replica set is recommended (single node replset is fine).
- Installing on localhost is recommended, to minimize latency and the potential for performance problems.
-
mongosh: https://www.mongodb.com/docs/mongodb-shell/install/
-
MongoDB Tools (
mongoimportandmongoexport): https://www.mongodb.com/docs/database-tools/ -
bash 5.3+ with
${;cmd;}patch installed in$PATHasbash-scas:git clone https://https.git.savannah.gnu.org/git/bash.git cd bash patch -p1 < /path/to/scas/bash-trailing_newline_nofork_comsub.patch ./configure && make -j$(nproc) ln -nsf $(pwd)/bash ~/bin/bash-scas # or anywhere that's in $PATH -
jq
sudo apt-get install jq -
podman (preferred), or docker:
sudo apt-get install podmanor
sudo apt-get install docker.io
-
Python MCP SDK (recommended, only needed for the
mcp-serveroperation):python3 -m pip install mcp -
Java (not necessary, only if re-enabling the legacy
enrich-java):sudo apt-get install openjdk-21-jdk maven
-
The default enricher
enrich-lspneedslsproxyto be built:lsproxy/scripts/build.sh -
The legacy
enrich-javaenricher (not enabled by default) needsjava-spoonto be built:cd java-spoon/scas-java-spoon mvn packageAfter building, ensure that there is a copy or symlink of the resulting
scas-java-spoon-1.0-SNAPSHOT-jar-with-dependencies.jarfile aslibexec/scas/scas-java-spoon.jar.
-
Test suite dependencies (beyond the above):
- Git
-
To run the test suite:
./run_testsThis will use the MongoDB instance/cluster specified by the connection string in
$SCAS_DB, defaulting tomongodb://localhost/scas. -
To run the unit tests:
./run_unittests
Setup
-
Checkout the repo:
git clone https://github.com/mongodb-labs/scas cd scas -
Decide where to install SCAS.
-
If you choose the checked-out git repo, then you only need to add the
bindir to$PATH:export PATH="$(pwd)/bin:$PATH"Consider adding this to the end of your
~/.profilefile. -
If another location, then ensure that the
bin/scasprogram can be found via$PATH. Then, you need to install the contents of thelibexec/scasdir to a place where it can be found, one of:/etc/xdg/scas/libexec(orscas/libexecunder an entry in$XDG_CONFIG_DIRS)libexec/scasor../libexec/scas(relative to wherebin/scashas been installed)/usr/libexec/scas
-
-
If
bash-scashasn't already been installed, you can do so now:git clone https://https.git.savannah.gnu.org/git/bash.git cd bash patch -p1 < ../bash-trailing_newline_nofork_comsub.patch ./configure && make -j$(nproc) cd ..If you installed SCAS:
-
To the checked-out git repo, then:
ln -nsf ../bash/bash bin/bash-scas -
To another location, then place the
bash-scassymlink (or copy thebashbinary asbash-scas) somewhere in the$PATH, ideally alongside thescassymlink/script.
-
-
(Optional) Initialise scas in each shell where it will be used (this enables the
scas -candscas -dcommands):source <(scas _shellinit bash)Consider adding this to the end of your
~/.profilefile. -
Set the connection string of the MongoDB instance/cluster that will be used (including DB name). Defaults to
mongodb://localhost/scas.# If step 2 above was done: scas -d 'mongodb://localhost/scas' # Otherwise: export SCAS_DB='mongodb://localhost/scas' -
Set the "name" for your repo. This will be the collection name under the db (if it already exists, it will be dropped).
# If step 2 above was done: scas -c my_repo_name # Otherwise: export SCAS_COLL=my_repo_name -
Parse your repo's source code.
scas parse /path/to/my/repo my_repo_parsed.json -
Import the parsed syntax tree into MongoDB.
scas import my_repo_parsed.json -
Enrich the syntax tree. This re-parses the original source code, which must not have changed.
scas enrich /path/to/my/repo
Usage - command line
- Run each operation with the
runoperation, passing in the source location of interest. Note thatrunexpects "normal" 1-indexed line/col numbers. Alternatively you can directly pass in node ids. eg:scas run ChangeLiteral 0.15 <<<test1.java:7:20scas run Rename discountNew <<<test1.java:23:20
Usage - editor integration
The only editor integration so far is vim (may not work yet in neovim, YMMV).
vim
-
Source the scas.vim file from your
~/.vimrc(or otherwise source/plugin manager it). -
Open the source files from the base dir of your repo (ie. from the
/path/to/my/repothat was passed toscas parseandscas enrichin the earlier steps). This is necessary so that the relative filenames match, and SCAS is able to properly apply the operations to the correct syntax tree nodes. (This restriction will eventually be removed.) -
To run a SCAS operation on the node targeted by the current cursor position, press Meta-s (Alt-s). This will open the vim command line with
:Scaspre-filled. You can now enter your SCAS operation and args, and press enter to execute it.The
Scasvim command will take care of automatically re-reading any open files that were modified (without modifying yourautoreadsetting). If the SCAS operation outputs any messages or errors, then those will be shown with a "Press Enter" prompt. Otherwise, the file is silently updated with the new contents.
The Meta-s (Alt-s) shortcut works in both normal and insert mode, but when using SCAS you shouldn't really ever be in insert mode, since you shouldn't modify the files except via SCAS. If you do modify the source files outside of SCAS, then you'll need to re-run the parse + import + enrich flow from scratch (steps 5-7 above).
Usage - MCP server (for AI agents)
The mcp-server operation runs an MCP (Model Context Protocol) server over stdio, exposing scas as a tool for AI agents. It requires the mcp Python package (pip install mcp).
-
Ensure that
$SCAS_COLLis set (and optionally$SCAS_DB), and that the codebase has been parsed, imported, and enriched (steps 3-7 above). -
Configure your MCP client to launch the scas MCP server. For example, in Claude Desktop's
claude_desktop_config.json:{ "mcpServers": { "scas": { "command": "scas", "args": ["mcp-server"], "env": { "SCAS_COLL": "my_repo_name" } } } }or in
opencode.jsonc:The server exposes a single
scastool that accepts a list of string arguments (equivalent to command-line arguments to thescasprogram). The tool returns structured output with fieldsrc(exit code),stdout, andstderr.
Usage - low level
Note that the run operation (described above) should be preferred to manually running operations low-level like this. The run operation automatically takes care of calling _FindNode, regenerate, etc.
-
Run an operation. See below for the operation API/protocol. Note that line/col numbers in SCAS are zero-indexed. eg:
scas _FindNode <<<test1.java:6:19 | scas _FirstNode | scas ChangeLiteral 0.15 -
Regenerate the source code files, and update the "locs" in the database.
scas regenerate --locs --files /path/to/output/repo -
Rinse and repeat for the next operation.
Debug
- To print the syntax tree stored in a collection, run:
scas regenerate --tree | less
Operations are programs, written in any language. They take arguments on the command line, and input on stdin. They output on stdout, and errors go to stderr and cause a non-zero exit code.
The input and output varies by operation, but is usually comprised of ids for syntax tree nodes, with each line containing a (possibly empty) list of whitespace-separated ids. Each line is considered to be a semantically separate set of ids. Each id is 40 hex digits (similar to git commit hashes). Operations may be read-only, or may modify the syntax tree. In either case, they expect $SCAS_COLL to be set (and $SCAS_DB, except that will default to mongodb://localhost/scas if unset).
_FindNode is a special operation. It takes locs as input, each of which specifies a location or range in the source code text files. The format is filename:start_line:start_col[-end_line:end_col], where filename is the name of the file (relative to the base of the repo, as passed to parse and enrich), and the start/end line/col numbers are zero-indexed (unlike the usual convention in text editors, compilers, etc). The end line/col numbers are optional, and if present, specify a range within the given source file (with the start line/col being inclusive, and the end line/col being exclusive). Otherwise, the start line/col numbers indicate an exact position in the source file. The _FindNode operation will query for syntax tree nodes which include the input loc, and output them from the most specific node (lowest level of the tree) up to the root node for that file. This serves as the most useful and convenient way of getting the ids of nodes that the programmer is interested in.
The syntax tree is stored as one document per tree node. Each node has an immutable _id (computed at parse time), with references to the ids of its parent and children nodes.
Any operation can connect to the database and query/update the syntax nodes, however, in general, if there is an existing operation which achieves the same result, then it is preferable to instead call that operation.
(TODO: describe the schema)
{ "mcp": { "scas": { "type": "local", "command": ["scas", "mcp-server"], "enabled": true, //"environment": { // "SCAS_COLL": "my_repo_name", // or just allow the value set in the environment, before loading opencode, to pass through //} } }, }