ββββββ βββ βββ
ββββββββββββββββ
ββββββββ ββββββ
ββββββββ ββββββ
βββ βββββββ βββ
βββ ββββββ βββ
"It sees your stack. It learns your structure. It writes what you'd spend hours crafting."
AX is a single-file, zero-dependency Bash utility that autonomously generates production-ready GitHub Actions CI/CD workflows. It scans your project's file tree, concurrently fingerprints every programming language present using its Hybrid Detection Engine, packages that intelligence into a structured prompt, and dispatches it to OpenAI GPT-4o β all while a live Cybernetic Eye animation renders in your terminal at 16 frames per second.
The result: a valid .github/workflows/main.yml tailored exactly to your stack, written in seconds, without you touching a YAML key.
Developer: Nikan Eidi β Computer Programming & Analysis Student
- System Architecture & Logic
- Hybrid Detection Engine
- Pseudocode β Core Execution Flows
- Technical Features
- Public Documentation Directory
- Installation & Usage
- Technical Stack
- Author
AX executes through a strict, seven-state linear pipeline. A global STATE variable transitions from IDLE through each named phase, providing a deterministic execution trace auditable at any point. Every transition is reflected in the live animation label running in parallel.
IDLE β SCANNING β BUILDING β REQUESTING β PARSING β WRITING β DONE
β
ERROR βββββββββββββββββ (any phase)
%%{init: {'theme': 'dark', 'themeVariables': {
'primaryColor': '#00fff7',
'primaryTextColor': '#ffffff',
'primaryBorderColor': '#c724b1',
'lineColor': '#c724b1',
'secondaryColor': '#0d0d0d',
'tertiaryColor': '#0d0d0d',
'background': '#0d0d0d',
'mainBkg': '#0d0d0d',
'nodeBorder': '#00fff7'
}}}%%
flowchart TD
ENTRY([β‘ ax β invoked from project root])
ENTRY --> A
subgraph P1 ["π PHASE 1 β TREE SCAN β’ STATE: SCANNING"]
A["get_project_tree()\nfind . -maxdepth 3 -not -path '*/.*'\ngrep -vE node_modules Β· .git Β· build Β· dist Β· bin Β· obj Β· target Β· venv\nsed pipeline β indented tree representation"]
end
subgraph P2 ["βοΈ PHASE 2 β HYBRID DETECTION β’ STATE: BUILDING"]
B["get_context()\nConcurrent manifest + glob checks\nAccumulate all hits into tags[] array\nNode Β· Python Β· Go Β· Rust Β· Java Β· C++ Β· Ruby Β· Shell Β· Windows"]
end
subgraph P3 ["π¦ PHASE 3 β PAYLOAD PACKAGING β’ STATE: BUILDING"]
C["create_payload()\npython3 -c json.dumps()\nInject system prompt with 8 directives\nax.sh explicitly excluded Β· temperature: 0.1"]
end
subgraph P4 ["π€ PHASE 4 β AI CONSULTATION β’ STATE: REQUESTING"]
D["request_ai()\ncurl -s -X POST api.openai.com/v1/chat/completions\nModel: gpt-4o Β· --max-time 60 Β· --connect-timeout 10\nCapture body + HTTP status via -w flag\nFull curl-exit + HTTP error classification matrix"]
end
subgraph P5 ["π§Ή PHASE 5 β YAML SANITISATION β’ STATE: PARSING"]
E["parse_response()\npython3 json.load via stdin\nre.sub strip ``` opening fence with optional lang tag\nre.sub strip ``` closing fence\nRoute API_ERROR Β· PARSE_ERROR prefix strings"]
end
subgraph P6 ["πΎ PHASE 6 β FILE WRITE β’ STATE: WRITING"]
F["mkdir -p .github/workflows/\nValidate final_yaml non-empty\necho final_yaml > main.yml\nCheck write success"]
end
subgraph P7 ["π PHASE 7 β GIT-SYNC PROMPT β’ STATE: DONE"]
G["prompt_git_sync()\n8-line TUI panel Β· tput sc/rc scroll-safe\nArrow-key + y/n/Enter/ESC input loop\ncommand -v git-sync before dispatch"]
end
ENTRY --> P1 --> P2 --> P3 --> P4 --> P5 --> P6 --> P7
A --> B --> C --> D --> E --> F --> G
D -- "NETWORK_ERROR\nAUTH_ERROR Β· RATE_ERROR\nSERVER_ERROR Β· HTTP_ERROR" --> ERR(["β‘ stop_loader\ntput cnorm\nprintf error msg\nexit 1"])
E -- "API_ERROR\nPARSE_ERROR\nempty output" --> ERR
F -- "mkdir failure\nwrite failure" --> ERR
G -- "YES + git-sync on PATH" --> SYNC["git-sync"]
G -- "YES + git-sync absent" --> MISS(["β‘ install hint\nexit 1"])
G -- "NO Β· ESC Β· n" --> OK(["β Graceful exit 0"])
SYNC --> OK
style P1 fill:#0d0d0d,stroke:#00fff7,color:#00fff7
style P2 fill:#0d0d0d,stroke:#c724b1,color:#c724b1
style P3 fill:#0d0d0d,stroke:#00fff7,color:#00fff7
style P4 fill:#0d0d0d,stroke:#c724b1,color:#c724b1
style P5 fill:#0d0d0d,stroke:#00fff7,color:#00fff7
style P6 fill:#0d0d0d,stroke:#c724b1,color:#c724b1
style P7 fill:#0d0d0d,stroke:#00fff7,color:#00fff7
style ERR fill:#3d0000,stroke:#ff0040,color:#ff4060
style MISS fill:#3d0000,stroke:#ff0040,color:#ff4060
style OK fill:#001a00,stroke:#00ff88,color:#00ff88
get_context() is AX's language fingerprinter. It performs a single-pass, non-exclusive concurrent check β every test runs independently, so matching Node.js never skips the Python or Go checks. Every hit appends a label to a local tags[] Bash array. The final ${tags[*]} expansion produces a space-separated context string that is passed verbatim into the GPT-4o user message.
# Exact source β get_context() in ax.sh
local tags=()
[ -f "package.json" ] && tags+=("Node.js")
([ -f "requirements.txt" ] || [ -f "pyproject.toml" ] || ls *.py &>/dev/null) && tags+=("Python")
([ -f "go.mod" ] || ls *.go &>/dev/null) && tags+=("Go")
([ -f "Cargo.toml" ] || ls *.rs &>/dev/null) && tags+=("Rust")
([ -f "pom.xml" ] || [ -f "build.gradle" ] || ls *.java &>/dev/null) && tags+=("Java")
(ls *.cpp &>/dev/null || ls *.c &>/dev/null || ls *.h &>/dev/null) && tags+=("C/C++")
([ -f "Gemfile" ] || ls *.rb &>/dev/null) && tags+=("Ruby")
(ls *.sh &>/dev/null) && tags+=("Shell")
(ls *.bat &>/dev/null || ls *.ps1 &>/dev/null) && tags+=("Windows-Script")
if [ ${#tags[@]} -eq 0 ]; then
echo "General/Single-File"
else
echo "${tags[*]}"
fi| Language Tag | Manifest Signal | Glob Signal | Detection Logic |
|---|---|---|---|
| Node.js | package.json |
β | Manifest only |
| Python | requirements.txt Β· pyproject.toml |
*.py |
Manifest OR glob |
| Go | go.mod |
*.go |
Manifest OR glob |
| Rust | Cargo.toml |
*.rs |
Manifest OR glob |
| Java | pom.xml Β· build.gradle |
*.java |
Manifest OR glob |
| C/C++ | β | *.cpp Β· *.c Β· *.h |
Glob only |
| Ruby | Gemfile |
*.rb |
Manifest OR glob |
| Shell | β | *.sh |
Glob only |
| Windows-Script | β | *.bat Β· *.ps1 |
Glob only |
Fallback: If tags[] remains empty after all checks, the function returns "General/Single-File" β the AI generates a safe minimal skeleton rather than failing.
Example β polyglot monorepo with 5 stacks present:
Node.js Python Go Rust ShellGPT-4o receives this string and produces a five-language hybrid workflow in a single API call.
PROCEDURE main():
SET state β SCANNING
START background loader WITH label "Scanning project structure..."
SET progress β 10%
CALL get_project_tree() β structure
ON FAILURE: stop loader Β· print "β‘ Failed to scan project tree." Β· EXIT 1
CALL get_context() β context
SET progress β 30%, label β "Building AI payload [ {context} ]..."
SET state β BUILDING
CALL create_payload(structure, context) β payload
IF payload IS EMPTY: stop loader Β· print "β‘ Payload is empty β aborting." Β· EXIT 1
SET progress β 50%, label β "Consulting OpenAI [ gpt-4o ]..."
SET state β REQUESTING
CALL request_ai(payload) β raw_response, req_status
IF req_status != 0 OR raw_response MATCHES (*_ERROR:*):
stop loader Β· print "β‘ {raw_response}" Β· SET state ERROR Β· EXIT 1
SET progress β 80%, label β "Parsing response..."
SET state β PARSING
CALL parse_response(raw_response) β final_yaml
IF final_yaml MATCHES "API_ERROR:*": stop loader Β· print OpenAI error Β· EXIT 1
IF final_yaml MATCHES "PARSE_ERROR*": stop loader Β· print parse error Β· EXIT 1
IF final_yaml IS EMPTY: stop loader Β· print empty error Β· EXIT 1
SET progress β 95%, label β "Writing workflow file..."
SET state β WRITING
CREATE directory .github/workflows/ ON FAIL: stop loader Β· EXIT 1
WRITE final_yaml β .github/workflows/main.yml
ON FAIL: stop loader Β· print "β‘ Failed to write main.yml" Β· EXIT 1
SET progress β 100%, label β "Complete!"
SET state β DONE
SLEEP 0.4 seconds
STOP loader
PRINT "[+] Success! .github/workflows/main.yml has been created."
CALL prompt_git_sync()
END PROCEDURE
PROCEDURE _loader_loop(stop_file, prog_file, label_file, line_count=18):
HIDE terminal cursor β tput civis
PRINT line_count blank lines β reserve vertical space
MOVE cursor UP line_count rows β \033[18A
SAVE cursor position β tput sc β scroll-safe absolute anchor
SET frame β 0
WHILE stop_file DOES NOT EXIST:
READ progress β prog_file (default: "0")
READ label β label_file (default: "Processing...")
RESTORE cursor to saved anchor β tput rc
COMPUTE blink_step β frame MOD 16
IF blink_step IN {0..9, 13..15} β eye_state = OPEN
ELIF blink_step IN {10, 12} β eye_state = HALF_CLOSED
ELIF blink_step = 11 β eye_state = FULLY_CLOSED
SELECT iris_glyph β ['β','β','β','β','β','β','β','β'] AT (frame MOD 8)
SELECT sparkle_glyphβ ['Β·','β','Β·','Β°','Β·','β','Β·','Β°'] AT (frame MOD 8)
SELECT spinner β braille 10-glyph set AT (frame MOD 10)
BUILD progress_bar β (progress Γ 24 / 100) Γ 'β' + remainder Γ 'β'
RENDER eye body β 13 lines (_eye_open / _eye_half / _eye_closed)
RENDER blank line β 1 line (\033[2K)
RENDER bar box top β 1 line (ββββββββββββββββββββββββββββββββββ)
RENDER bar row β 1 line (β {bar} {progress}% β)
RENDER bar box bot β 1 line (ββββββββββββββββββββββββββββββββββ)
RENDER label line β 1 line ({spinner} {label})
// Total = 18 lines β invariant must never drift
frame β frame + 1
SLEEP 0.06 seconds β β 16 fps
END WHILE
RESTORE cursor to anchor β tput rc
ERASE 18 lines β \033[2K\n Γ 18
RESTORE cursor to anchor β tput rc
SHOW terminal cursor β tput cnorm
END PROCEDURE
The animation is a parallel background process that communicates with the parent process entirely through three shared tmpfiles. It renders an 18-line deterministic block at approximately 16fps using raw ANSI escape sequences and tput for all cursor operations.
Parent Process (main) Background Subshell (_loader_loop &)
βββββββββββββββββββββ ββββββββββββββββββββββββββββββββββββββ
start_loader()
mktemp β /tmp/ci_stop.XXXXXX ββ Polls: while [ ! -f "$stop_file" ]
mktemp β /tmp/ci_prog.XXXXXX β Reads: progress each frame
mktemp β /tmp/ci_label.XXXXXX β Reads: label each frame
rm -f $_STOP_FILE Loop runs while stop file is ABSENT
echo "0" > $_PROG_FILE
echo "$label" > $_LABEL_FILE
_loader_loop ... &
LOADER_PID=$!
set_loader_progress 80 "Parsing..."
echo "80" > $_PROG_FILE β Next frame reads "80" for bar render
echo "Parsing" > $_LABEL_FILE β Next frame reads new label text
stop_loader()
touch "$_STOP_FILE" β Loop detects file Β· exits cleanly
wait "$LOADER_PID"
rm -f all three tmpfiles
clear all global variables
No signals, no pipes, no subshell variable scope leakage β the entire IPC channel is three files in /tmp/.
Every call to _draw_frame() emits exactly 18 lines. This invariant is what makes the tput rc cursor-rewind safe β if any frame emits 17 or 19 lines, all subsequent frames drift permanently.
| Lines | Component | Emitted By |
|---|---|---|
| 13 | Eye body | _eye_open() Β· _eye_half() Β· _eye_closed() |
| 1 | Blank separator | printf '%s\n' "$CLR" |
| 1 | Bar box top | ββββββββββββββββββββββββββββββββββ |
| 1 | Bar row | β ββββββββββββββββββββββββ 50% β |
| 1 | Bar box bottom | ββββββββββββββββββββββββββββββββββ |
| 1 | Animated label | β Ή Consulting OpenAI [ gpt-4o ]... |
| 18 | Total β invariant |
# Exact source β _draw_frame() in ax.sh
local step=$(( f % 16 ))
local eye_state="open"
[[ $step -eq 10 || $step -eq 12 ]] && eye_state="half"
[[ $step -eq 11 ]] && eye_state="closed"Frame: 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
State: [ββββββββββββββββ OPEN ββββββββββββ] [HALF] [SHUT] [HALF] [OPEN]
Three independent animation counters run simultaneously:
| Glyph Set | Array | Cycle | Counter |
|---|---|---|---|
| Iris center | β β β β β β β β |
8 frames | f % 8 |
| Pupil sparkle | Β· β Β· Β° Β· β Β· Β° |
8 frames | f % 8 |
| Status spinner | 10 Braille chars | 10 frames | f % 10 |
Each cycles independently of the 16-frame blink, producing organic asynchronous micro-animation across all eye states.
# FRAGILE β breaks on any terminal scroll event
printf "\033[18A"
# CORRECT β used throughout ax.sh
tput sc # Saves absolute cursor address in terminal's own state memory
# ... render 18 lines ...
tput rc # Restores that absolute address β unaffected by scroll\033[nA (cursor-up N rows) is relative to the current viewport top. A single scroll event during the API call shifts the viewport, making the count wrong β all subsequent frames render at the wrong position with no recovery. tput sc stores an absolute cursor coordinate in the terminal emulator's own memory. tput rc retrieves it unconditionally regardless of how much the viewport has scrolled.
Each sub-renderer prints exactly 13 lines β the contract that upholds the 18-line budget:
| Function | Eye State | Frames | Signature Visual |
|---|---|---|---|
_eye_open() |
Fully open | 0β9, 13β15 | Tiered lashes Β· sclera dots Β· live iris ring Β· animated pupil |
_eye_half() |
Half-closed | 10, 12 | Descending βββ lid Β· iris arc peeking Β· drooping lashes |
_eye_closed() |
Fully sealed | 11 | βββββ border Β· neon βββ seam Β· βββ/βββ fill Β· flat lashes |
_eye_open() receives the current frame number and applies an additional iris ring flicker: when f % 4 == 0, the ring color shifts to ${BOLD}${GLOW}, creating a 4-frame brightness pulse layered on top of all other animation cycles.
# Exact source β _build_bar() in ax.sh
local width=24
local filled=$(( prog * width / 100 ))
local empty=$(( width - filled ))
local bar="" spaces=""
for ((i=0; i<filled; i++)); do bar+="β"; done
for ((i=0; i<empty; i++)); do spaces+="β"; done
printf "%s" "${CYAN}${BOLD}${bar}${R}${DIM}${MAG}${spaces}${R}"A 24-character wide bar: filled blocks in ${CYAN}${BOLD}, empty blocks in ${DIM}${MAG}. Integer division ensures the bar never overflows.
A ghost dependency is a CI step generated for a language that is not a genuine project requirement β introduced only because a build utility or AX itself happens to use that language.
AX prevents this at the system prompt level inside create_payload(). Three directives are injected into every GPT-4o call:
# Exact source β create_payload() embedded Python in ax.sh
system_prompt = (
"You are a Senior DevOps Architect. Analyze the project tree and detected contexts. "
"IDENTIFICATION: Identify the ACTUAL project types. If multiple languages are present, create a hybrid workflow. "
"EXCLUSION: Completely IGNORE the file ax.sh. "
"MINIMALISM: If the project has only shell scripts and no manifest files, "
"generate a workflow with exactly two steps: "
"step 1 β checkout code with actions/checkout@v4; "
"step 2 β a step named Lint shell scripts that runs the following command exactly: "
"find . -name SINGLEQUOTE*.shSINGLEQUOTE -not -path SINGLEQUOTE*/.*SINGLEQUOTE | xargs shellcheck --severity=warning "
"In the final YAML output replace every token SINGLEQUOTE with an actual single-quote character. "
"NO GHOST DEPENDENCIES: Never add setup steps for languages not evidenced by real source files. "
"SINGLE FILE: If only one or two standalone files exist, create a minimalist CI for them. "
"CLEAN OUTPUT: Output ONLY raw YAML β no markdown, no commentary, no preamble. "
"STANDARDS: Always use runs-on: ubuntu-latest and actions/checkout@v4."
)What each ghost-prevention directive solves:
| Directive | Ghost Scenario Prevented |
|---|---|
EXCLUSION: Completely IGNORE the file ax.sh |
AX's own *.sh script triggers a shellcheck step in a pure Python project |
MINIMALISM: If only shell scripts...exactly two steps |
Shell-only project gets a bloated multi-step workflow instead of just checkout + shellcheck |
NO GHOST DEPENDENCIES: Never add setup steps... |
AI hallucinates Node.js or Java setup steps because the tree looks like it might need them |
The SINGLEQUOTE token pattern: The MINIMALISM directive must embed find . -name '*.sh' inside the JSON payload string. Single quotes inside a Python sys.argv string create multi-layer quoting conflicts. AX uses a token substitution: the literal string SINGLEQUOTE is written in the prompt, and the AI is instructed to replace every occurrence with an actual ' character in its YAML output. This produces a syntactically correct find command in the workflow with no escaping complexity in the Bash or Python layers.
The temperature: 0.1 setting reinforces determinism: the same scanned structure produces functionally equivalent workflows across repeated runs.
After a successful write, prompt_git_sync() renders an 8-line interactive confirmation panel using the same tput sc/rc scroll-safe cursor technique as the animation loop. It implements a complete raw keyboard event loop with IFS= read -rsn1.
ββββββββββββββββββββββββββββββββββββββββββββββ
β [!] EXECUTE GIT-SYNC? β
β Would you like to run git-sync now? β
β βββββββββββββββββ¦ββββββββββββββββββββββββββββ£
β > YES < β NO β β selected = 0
β βββββββββββββββββ©ββββββββββββββββββββββββββββ£
β ββ YES ββ NO β΅ confirm y/n quick β
ββββββββββββββββββββββββββββββββββββββββββββββ
The box inner width is 44 characters β split into a 16-char left cell (YES) and a 27-char right cell (NO), joined by a β¦/β© column divider. The active option is highlighted using ${BOLD}${REV} (reverse video), redrawing on every navigation event for immediate visual feedback.
# Exact source β prompt_git_sync() event loop in ax.sh
IFS= read -rsn1 key # Read exactly 1 raw byte
if [[ "$key" == $'\033' ]]; then # ESC detected (0x1B)
IFS= read -rsn1 -t 0.05 seq # Read 2nd byte (50ms timeout)
if [[ "$seq" == '[' ]]; then
IFS= read -rsn1 -t 0.05 key # Read 3rd byte: direction char
case "$key" in
A|D) selected=0 ;; # β Up or β Left β YES
B|C) selected=1 ;; # β Down or β Right β NO
esac
tput rc 2>/dev/null # Restore to panel top
_draw_prompt "$selected" # Immediate redraw
continue
fi
selected=1; break # Lone ESC β cancel = NO
fi
case "$key" in
y|Y) selected=0; break ;; # Direct YES, no Enter needed
n|N) selected=1; break ;; # Direct NO, no Enter needed
$'\n'|$'r'|'') break ;; # Enter β confirm current selection
esac| Key Input | Raw Bytes | Action |
|---|---|---|
β Up arrow |
1B 5B 41 (ESC [ A) |
Select YES |
β Left arrow |
1B 5B 44 (ESC [ D) |
Select YES |
β Down arrow |
1B 5B 42 (ESC [ B) |
Select NO |
β Right arrow |
1B 5B 43 (ESC [ C) |
Select NO |
y or Y |
1 byte | Confirm YES instantly (no Enter required) |
n or N |
1 byte | Confirm NO instantly (no Enter required) |
Enter / β΅ |
0x0A |
Confirm current selection |
ESC (lone) |
0x1B + 50ms silence |
Cancel β NO |
The lone-ESC detection relies on a 50ms timeout on the follow-up read. If no second byte arrives within 50ms of the ESC, it is classified as a standalone Escape keypress (cancel β NO), not the start of an arrow sequence. After any confirmation, the panel is wiped with 8Γ \033[2K\n, the cursor is restored to the panel origin, and AX either runs git-sync (after a command -v guard) or exits gracefully with code 0.
The /public directory ships four companion reference documents providing complete engineering transparency for every layer of AX.
A structured mapping of every user-facing feature to its implementing function(s), execution phase, and dependencies. Covers 96 traced features across seven sections: Core Pipeline, State Machine, Animation System, Ghost-Dependency Prevention, TUI & Interaction, Error Handling, and Visual/ANSI.
Use this document for code review, regression auditing, and contributor onboarding.
A complete function-level API reference for every Bash function and embedded Python3 helper in ax.sh. Each entry documents: purpose, full signature, typed parameter table, return values, side effects, step-by-step execution sequence, error behaviour, and design rationale notes.
Includes a global variable reference table and the full ANSI 256-color variable reference.
All 21 functions documented: main Β· set_state Β· get_state Β· cleanup Β· on_error Β· start_loader Β· stop_loader Β· set_loader_progress Β· _loader_loop Β· _draw_frame Β· _build_bar Β· _eye_open Β· _eye_half Β· _eye_closed Β· get_project_tree Β· get_context Β· create_payload Β· request_ai Β· parse_response Β· prompt_git_sync Β· _draw_prompt
Formal test scenario specifications for 20 test cases covering the full surface area of AX β pipeline correctness, AI output quality, error handling, animation resilience, and TUI edge cases. Every case includes exact environment setup scripts, expected outputs, pass criteria, and fail indicators.
| ID | Name | What It Validates |
|---|---|---|
| TC-001 | The Chonk-Meter | 5-language monorepo β hybrid workflow Β· zero ghost steps |
| TC-002 | Hybrid Stress Test | Node + Python β exact two-language workflow only |
| TC-003 | Ghost-Dep Isolation | Shell-only β exactly 2 steps Β· ax.sh never referenced |
| TC-005 | Auth Error Handling | Missing key β AUTH_ERROR: Β· exit 1 Β· clean terminal |
| TC-006 | SIGINT Resilience | Ctrl+C at any phase β exit 130 Β· cursor restored Β· no orphan PIDs |
| TC-011 | Fence Stripping | 4 fence variants β identical clean YAML output |
| TC-014 | Animation Scroll Safety | Viewport scroll during API call β animation stays aligned |
A deep-dive technical architecture reference covering every structural and design decision in ax.sh. Topics include: the 4-stage find | grep | sed tree scanner pipeline and why maxdepth 3, the hybrid detection array accumulation pattern, the SINGLEQUOTE token substitution design, the tmpfile IPC architecture, the tput sc/rc vs \033[nA rationale, the 3-byte ESC sequence input parser, the 18-line frame budget invariant, the temperature: 0.1 selection reasoning, the ERR trap $LINENO deferred expansion, and the complete external command dependency map.
| Requirement | Minimum Version | Role in AX |
|---|---|---|
| Bash | 4.0+ | Runtime β indexed array syntax requires v4 |
| Python 3 | 3.7+ | create_payload() and parse_response() β stdlib only (json, re, sys) |
| curl | 7.x+ | HTTP POST to OpenAI β -w status capture requires 7.x |
| OpenAI API Key | β | GPT-4o access |
| git-sync | any | (Optional) β only invoked if you confirm YES at the TUI prompt |
git clone https://github.com/<your-username>/ax.git
cd axsudo cp ax.sh /usr/local/bin/ax
sudo chmod +x /usr/local/bin/axVerify the installation:
which ax
# β /usr/local/bin/axZsh (recommended):
echo 'export OPENAI_API_KEY="sk-your-key-here"' >> ~/.zshrc
source ~/.zshrcBash:
echo 'export OPENAI_API_KEY="sk-your-key-here"' >> ~/.bashrc
source ~/.bashrcConfirm it is set:
echo $OPENAI_API_KEY
# β sk-your-key-here
β οΈ Security: Never commit your API key to version control. For per-project key isolation, usedirenvwith a.envrcfile added to your.gitignore.
cd /path/to/your/project
axAX will scan, detect, consult GPT-4o, sanitise the response, and write the workflow β all with the Cybernetic Eye animation tracking each phase. When complete, the TUI prompts for git-sync.
Generated output:
.github/
βββ workflows/
βββ main.yml β production-ready, stack-accurate CI workflow
cd /path/to/ax-repo
git pull origin main
sudo cp ax.sh /usr/local/bin/ax| Layer | Technology | Role in AX |
|---|---|---|
| Runtime | Bash 4+ | All orchestration, state machine, IPC, signal handling, TUI event loop |
| Data Serialisation | Python 3 β json Β· re Β· sys |
create_payload(): json.dumps() for safe JSON build Β· parse_response(): re.sub() for fence stripping and json.load() for response parsing |
| AI Engine | OpenAI GPT-4o (gpt-4o) |
Single completions call per run Β· temperature: 0.1 for determinism Β· system prompt with 8 behavioural directives |
| HTTP Transport | curl 7.x |
-s -w dual-capture (body + HTTP code) Β· --max-time 60 Β· --connect-timeout 10 Β· full curl-exit-code + HTTP-status error matrix |
| Terminal Colour | ANSI 256-color escapes | \033[38;5;{n}m foreground palette β 10 named colors + DIM Β· BOLD Β· REV Β· CLR modifiers |
| Cursor Control | tput (ncurses) |
tput sc/rc scroll-safe anchor Β· tput civis/cnorm cursor hide/show Β· tput rev reverse-video highlighting |
| Parallel Process | Bash subshell & |
_loader_loop runs detached Β· LOADER_PID tracked Β· wait for clean join on stop |
| IPC | mktemp tmpfiles |
Three files in /tmp/ β progress integer Β· label string Β· stop sentinel (existence-based signal) |
| Signal Handling | trap |
INT TERM HUP β cleanup() (exit 130) Β· ERR β on_error $LINENO (exit original code) |
| Raw Input | read -rsn1 |
3-byte ESC sequence detection for arrow keys Β· 50ms timeout for lone-ESC disambiguation |
Nikan Eidi Computer Programming & Analysis Student
"AX started as a workflow generator. It became a study in how far you can push a terminal."
β‘ See the structure. Generate the workflow. Own the pipeline. β‘