Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 12 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,12 @@
# magic-code

**Open-source TUI agentic AI coding agent.** Built in Rust. Fast. Multi-provider.
[![CI](https://github.com/kienbui1995/mc-code/actions/workflows/ci.yml/badge.svg)](https://github.com/kienbui1995/mc-code/actions/workflows/ci.yml)
[![Security](https://github.com/kienbui1995/mc-code/actions/workflows/security.yml/badge.svg)](https://github.com/kienbui1995/mc-code/actions/workflows/security.yml)
[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
[![Release](https://img.shields.io/github/v/release/kienbui1995/mc-code)](https://github.com/kienbui1995/mc-code/releases)
[![crates.io](https://img.shields.io/crates/v/magic-code.svg)](https://crates.io/crates/magic-code)

**Open-source TUI agentic AI coding agent.** Built in Rust. Fast. Multi-provider. Self-hostable.

```
┌─ magic-code ████████░░ 62% ──────────────────────────────┐
Expand Down Expand Up @@ -32,6 +38,11 @@
curl -fsSL https://raw.githubusercontent.com/kienbui1995/mc-code/main/install.sh | sh
```

### Via cargo
```bash
cargo install magic-code
```

### Download binary
Pre-built binaries for Linux (x86_64, aarch64) and macOS (x86_64, aarch64):
```bash
Expand Down
11 changes: 11 additions & 0 deletions examples/batch-review.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
#!/bin/bash
# Batch code review: review multiple files
# Usage: ./batch-review.sh src/*.rs

TMPFILE=$(mktemp)
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The temporary file created with mktemp is not cleaned up if the script is interrupted (e.g., via Ctrl+C) or fails before reaching the explicit rm command. It is safer to use a trap to ensure the file is removed upon exit.

Suggested change
TMPFILE=$(mktemp)
TMPFILE=$(mktemp)
trap 'rm -f "$TMPFILE"' EXIT

for file in "$@"; do
echo "Review $file for bugs, security issues, and improvements. Be specific about line numbers." >> "$TMPFILE"
done

magic-code --yes --json --batch "$TMPFILE"
rm "$TMPFILE"
Comment on lines +5 to +11
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

🧩 Analysis chain

🏁 Script executed:

# Check if the file exists and examine its full contents
find . -name "batch-review.sh" -type f

Repository: kienbui1995/mc-code

Length of output: 89


🏁 Script executed:

# If file exists, read its full contents
cat examples/batch-review.sh 2>/dev/null || echo "File not found"

Repository: kienbui1995/mc-code

Length of output: 371


🏁 Script executed:

# Verify the script's current state matches the snippet
wc -l examples/batch-review.sh 2>/dev/null || echo "Cannot determine line count"

Repository: kienbui1995/mc-code

Length of output: 90


Harden temp-file lifecycle and empty-args behavior.

The script creates a temp file without cleanup on failure or interruption, and silently accepts zero arguments, creating an empty batch file. Add an EXIT trap for cleanup, set -euo pipefail for safety, an argument guard, and use printf for portability.

Suggested patch
 #!/bin/bash
 # Batch code review: review multiple files
 # Usage: ./batch-review.sh src/*.rs
+set -euo pipefail
+
+if [ "$#" -eq 0 ]; then
+    echo "Usage: ./batch-review.sh <files...>" >&2
+    exit 2
+fi
 
 TMPFILE=$(mktemp)
+trap 'rm -f "$TMPFILE"' EXIT
 for file in "$@"; do
-    echo "Review $file for bugs, security issues, and improvements. Be specific about line numbers." >> "$TMPFILE"
+    printf 'Review %s for bugs, security issues, and improvements. Be specific about line numbers.\n' "$file" >> "$TMPFILE"
 done
 
 magic-code --yes --json --batch "$TMPFILE"
-rm "$TMPFILE"
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@examples/batch-review.sh` around lines 5 - 11, The script currently creates
TMPFILE with mktemp and writes to it without ensuring cleanup on failure or
interruption and allows running with zero args; add a strict shell header (set
-euo pipefail) and an early argument guard that exits with a usage message if
"$#" is zero, replace echo with printf for portability when writing the per-file
review prompts to TMPFILE, and register a trap 'trap "rm -f \"$TMPFILE\"" EXIT'
immediately after creating TMPFILE so the temp file is removed on any exit;
update references to TMPFILE and the magic-code --yes --json --batch "$TMPFILE"
invocation accordingly.

22 changes: 22 additions & 0 deletions examples/ci-fix.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
#!/bin/bash
# CI/CD: Auto-fix failing tests with magic-code
# Usage: ./ci-fix.sh
set -e
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

Using set -e in combination with manual exit status checks (like if [ $? -eq 0 ] on line 13) can lead to unexpected behavior. If magic-code fails, the script will terminate immediately at line 11, making the else block on line 16 unreachable. It is generally better to avoid set -e when you intend to handle errors manually.


echo "Running tests..."
if cargo test --workspace 2>&1 | tail -5 | grep -q "FAILED"; then
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

Restricting the failure check to the last 5 lines of output using tail -5 is brittle. If the "FAILED" indicator is pushed further up by other output, grep will fail, and the script will incorrectly report "All tests pass." despite the actual failure. This could lead to false positives in CI.

Suggested change
if cargo test --workspace 2>&1 | tail -5 | grep -q "FAILED"; then
if cargo test --workspace 2>&1 | grep -q "FAILED"; then

echo "Tests failed. Asking magic-code to fix..."
magic-code --yes --json \
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

In an automated CI/CD context, the bash tool will still prompt for user confirmation unless the --dangerously-allow-bash flag is provided, even if --yes is used. To ensure the script runs headlessly as intended, you should include this flag.

Suggested change
magic-code --yes --json \
magic-code --yes --dangerously-allow-bash --json \

"The tests are failing. Read the test output, find the bug, and fix it. Run tests again to verify." \
-o fix-result.json
Comment on lines +9 to +11
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Verify `--json` return path occurs before `-o` output write handling.
rg -n -C4 'if json_output|if let Some\(path\) = output_path|return Ok\(\);' mc/crates/mc-cli/src/main.rs

Repository: kienbui1995/mc-code

Length of output: 726


--json bypasses -o output file creation due to early return.

The function returns at line 1722 after printing JSON output, before reaching the -o file-write logic at lines 1724-1726. Using both --json and -o together will silently ignore the output file flag. Redirect stdout or drop --json if an artifact is required.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@examples/ci-fix.sh` around lines 9 - 11, The CLI currently prints JSON and
returns early when the --json flag is set, which prevents the -o output-file
logic from running; update the command handling so that when both --json and -o
are provided the JSON is written to the specified file instead of (or in
addition to) only printing to stdout. Change the handler that prints JSON to
either: a) write the JSON string to the path from the -o option before
returning, or b) skip the early return and funnel the same JSON payload into the
existing file-write routine used by the -o branch; ensure you reference the
--json flag handling and the -o output-file logic so both paths produce the
artifact.


if [ $? -eq 0 ]; then
echo "Fix applied. Re-running tests..."
cargo test --workspace
else
echo "magic-code could not fix the issue."
exit 1
fi
Comment on lines +7 to +19
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

cat -n examples/ci-fix.sh

Repository: kienbui1995/mc-code

Length of output: 842


Failure detection via pipeline loses cargo test exit code; $? check is dead code due to set -e.

The pipeline on line 7 loses the cargo test exit code. If tests fail without "FAILED" appearing in the last 5 lines, the condition evaluates false and the else block incorrectly reports success. Additionally, with set -e active, the else block (lines 16–18) is unreachable—if magic-code fails, the script exits immediately rather than executing that branch.

Suggested patch
 echo "Running tests..."
-if cargo test --workspace 2>&1 | tail -5 | grep -q "FAILED"; then
+TEST_LOG=$(mktemp)
+trap 'rm -f "$TEST_LOG"' EXIT
+
+if ! cargo test --workspace >"$TEST_LOG" 2>&1; then
     echo "Tests failed. Asking magic-code to fix..."
-    magic-code --yes --json \
-        "The tests are failing. Read the test output, find the bug, and fix it. Run tests again to verify." \
-        -o fix-result.json
-    
-    if [ $? -eq 0 ]; then
+    if magic-code --yes --json \
+        "The tests are failing. Use this test output to find and fix the bug:
+$(tail -n 200 "$TEST_LOG")
+Run tests again to verify." \
+        -o fix-result.json; then
         echo "Fix applied. Re-running tests..."
         cargo test --workspace
     else
         echo "magic-code could not fix the issue."
         exit 1
     fi
 else
     echo "All tests pass."
 fi
🧰 Tools
🪛 Shellcheck (0.11.0)

[style] 13-13: Check exit code directly with e.g. 'if mycmd;', not indirectly with $?.

(SC2181)

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@examples/ci-fix.sh` around lines 7 - 19, Capture cargo test's exit status and
output instead of relying on tail+grep and make magic-code failure reachable by
not letting set -e short-circuit; specifically, run cargo test --workspace with
its stdout/stderr redirected into a variable/file (e.g., test_output="$(cargo
test --workspace 2>&1)" and test_exit=$?), then inspect test_exit (and
optionally grep "$test_output" for "FAILED") to decide whether to invoke
magic-code; likewise run magic-code in a way that preserves its exit code (e.g.,
magic-code ... -o fix-result.json; magic_exit=$?) and branch on magic_exit to
either re-run cargo test or print the failure message and exit non-zero,
updating the script's cargo test / magic-code checks instead of relying on
tail/grep and unsettable set -e behavior.

else
echo "All tests pass."
fi
17 changes: 17 additions & 0 deletions examples/config-selfhosted.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
# Self-hosted config: Qwen 3.5 via LiteLLM (zero cost)
# Copy to .magic-code/config.toml

[default]
model = "qwen3.5-9b"
provider = "litellm"
base_url = "http://localhost:4000"
max_tokens = 4096
notifications = false
Comment on lines +4 to +9
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

base_url and notifications look scoped to the wrong section.

DefaultLayer (from mc/crates/mc-config/src/types.rs) does not define these keys, so placing them under [default] risks silently ignoring them. Please move provider-level and runtime-level keys to their supported sections so this self-hosted example actually targets localhost:4000.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@examples/config-selfhosted.toml` around lines 4 - 9, The TOML example places
provider-level key "base_url" and runtime-level key "notifications" under the
[default] section, but DefaultLayer (mc/crates/mc-config/src/types.rs) does not
accept those keys so they will be ignored; move "provider" and "base_url" into
the provider-specific section (e.g., [providers.litellm] or whatever provider
block your config uses) and move "notifications" into the runtime or top-level
section that the config expects (e.g., [runtime] or the top-level flags) so the
self-hosted example actually applies to localhost:4000 and enables/disables
notifications correctly. Ensure keys remain named exactly "base_url" and
"notifications" and reference the same provider name "litellm" used in the
[default] model mapping.


# Memory
[memory]
max_facts = 100

# Managed agents (disabled for small models)
[managed_agents]
enabled = false
33 changes: 33 additions & 0 deletions examples/demo.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
#!/bin/bash
# Record a demo with: asciinema rec demo.cast
# Convert to GIF with: agg demo.cast demo.gif
# Or use: svg-term --in demo.cast --out demo.svg

echo "=== magic-code demo ==="
echo ""
echo "# 1. Quick fix"
echo '$ magic-code "fix the typo in src/main.rs"'
echo ""
sleep 1

echo "# 2. Self-hosted (zero cost)"
echo '$ magic-code --provider ollama --model qwen3.5:9b "add error handling"'
echo ""
sleep 1

echo "# 3. CI/CD integration"
echo '$ magic-code --yes --json "fix failing tests" -o result.json'
echo ""
sleep 1

echo "# 4. Batch processing"
echo '$ magic-code --yes --batch tasks.txt'
echo ""
sleep 1

echo "# 5. NDJSON streaming"
echo '$ magic-code --ndjson "explain auth.rs" | jq .type'
echo ""

echo "=== Install ==="
echo "curl -fsSL https://raw.githubusercontent.com/kienbui1995/mc-code/main/install.sh | sh"
15 changes: 15 additions & 0 deletions examples/stream-events.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
#!/bin/bash
# NDJSON streaming: pipe magic-code events to a web app
# Usage: ./stream-to-webapp.sh "your prompt"
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The usage example in the comment refers to a different filename (stream-to-webapp.sh) than the actual file (stream-events.sh).

Suggested change
# Usage: ./stream-to-webapp.sh "your prompt"
# Usage: ./stream-events.sh "your prompt"


magic-code --yes --ndjson "$1" | while IFS= read -r line; do
Comment on lines +3 to +5
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

🧩 Analysis chain

🏁 Script executed:

# First, check if examples/stream-events.sh exists and read its content
cat -n examples/stream-events.sh

Repository: kienbui1995/mc-code

Length of output: 676


🏁 Script executed:

# Check if stream-to-webapp.sh exists
fd -a "stream-to-webapp" examples/

Repository: kienbui1995/mc-code

Length of output: 45


🏁 Script executed:

# List all files in examples directory to understand the structure
ls -la examples/

Repository: kienbui1995/mc-code

Length of output: 430


Fix usage string and validate prompt input.

The usage line references a non-existent script name stream-to-webapp.sh instead of the actual script name stream-events.sh, and $1 is used without an argument check. Users calling this script without arguments will pass an empty string to magic-code.

Suggested patch
 #!/bin/bash
 # NDJSON streaming: pipe magic-code events to a web app
-# Usage: ./stream-to-webapp.sh "your prompt"
+# Usage: ./stream-events.sh "your prompt"
+set -euo pipefail
+
+if [ "$#" -lt 1 ]; then
+    echo 'Usage: ./stream-events.sh "your prompt"' >&2
+    exit 2
+fi
 
 magic-code --yes --ndjson "$1" | while IFS= read -r line; do
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@examples/stream-events.sh` around lines 3 - 5, Update the usage message in
examples/stream-events.sh to reference the correct script name
"stream-events.sh" and add a check for the prompt argument ($1) before calling
magic-code; if $1 is empty or missing, print the corrected usage string and exit
with a non-zero status. Specifically, adjust the header line that currently
mentions "stream-to-webapp.sh" to "stream-events.sh", validate $1 (the prompt)
at the top of the script, and only run the pipeline magic-code --yes --ndjson
"$1" | while IFS= read -r line; do when the argument is present.

type=$(echo "$line" | jq -r '.type // empty' 2>/dev/null)
case "$type" in
text)
echo "$line" | jq -r '.content' ;;
tool_call)
echo "[TOOL] $(echo "$line" | jq -r '.name')" ;;
tool_output)
echo "[OUTPUT] $(echo "$line" | jq -r '.content' | head -5)" ;;
esac
done
2 changes: 2 additions & 0 deletions mc/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ publish = false
rust-version = "1.75"
repository = "https://github.com/kienbui1995/mc-code"
description = "Open-source TUI agentic AI coding agent"
keywords = ["ai", "coding", "agent", "tui", "llm"]
categories = ["command-line-utilities", "development-tools"]

[workspace.lints.rust]
unsafe_code = "forbid"
Expand Down
Loading