Skip to content

Add C as a supported output language#105

Open
jarsh921 wants to merge 4 commits into
kalil0321:mainfrom
jarsh921:add-c-output-language
Open

Add C as a supported output language#105
jarsh921 wants to merge 4 commits into
kalil0321:mainfrom
jarsh921:add-c-output-language

Conversation

@jarsh921

@jarsh921 jarsh921 commented Jul 21, 2026

Copy link
Copy Markdown

Follows the same overall pattern as python/javascript/typescript, but C is genuinely different from every language added so far in two ways, both addressed directly in the new partial
(prompts/partials/_language_c.md):

  1. No stdlib HTTP or JSON. Unlike Go/PHP/Ruby (all fully dependency-free via their own standard libraries), C has neither. Uses libcurl for HTTP and vendors cJSON (a small, widely-used, permissively-licensed single-file JSON library) for JSON, rather than hand-rolling either - same reasoning as the Java PR's Gson choice: a real, tested library beats ad-hoc parsing written from scratch. libcurl itself is a system library a build step can't fetch, so the partial calls out installing it via the platform's package manager if the compiler can't find curl/curl.h.

  2. Compiled, not run directly - the only such language here. Every other language's {run_command} is (or now points at) a single interpreter/build-tool invocation; C needs an explicit compile step first. _get_run_command() chains cc <source> <cJSON.c> -lcurl -o <binary> && <binary> as one command, using full paths throughout for the same reason already fixed on the Go/Java/C#/PHP/Ruby PRs - the agent's cwd is scripts_dir.parent.parent, not scripts_dir where everything is actually saved.

base_engineer.py: added "c" to _OUTPUT_LANGUAGE_EXTENSIONS (.c) and _get_language_name() ("C"). _get_auto_output_files() always lists the vendored cJSON.c/cJSON.h (not conditional - C always needs them, no stdlib fallback, matching Java's always-included pom.xml rather than javascript/go's conditional dependency files).

cli.py: added C to the interactive output_language config picker. Updated the three docstrings/comments listing the language set (config.py, engineer.py, prompts/init.py) and README.md's output language line. Tests mirror the existing per-language pattern in both test_base_engineer.py and test_prompts.py.

Checked for the literal-brace str.format_map() bug caught in the Java PR - no literal {/} anywhere in the new partial.

Full test suite passes (49/49, run 3x) except the same pre-existing flaky test noted on the other language PRs. ruff check clean on every file this touches (8 pre-existing lint errors elsewhere on main, none in the touched lines).


Summary by cubic

Adds C as a supported output language, generating a libcurl + cJSON client that compiles and runs in one step. Vendors pinned cJSON and stops host installs; the compile-and-run command now resolves absolute paths and shell-quotes via shlex.

  • New Features

    • C codegen partial with C-specific guidance (reuse one CURL handle, error checks, auth hardcoding + refresh, cookie engine).
    • Compile-and-run command with resolved absolute paths and safe quoting: cc <source> <cJSON.c> -lcurl -o <binary> && <binary>.
    • Saves cJSON.c/cJSON.h with the client and fetches pinned cJSON v1.7.18 from upstream; if curl/curl.h is missing, surface a clear prerequisite error (no auto-install). Updated CLI picker, docs, and tests.
  • Migration

    • Requires system libcurl headers to compile (install your platform’s package before running).

Written for commit 971df93. Summary will update on new commits.

Review in cubic

Greptile Summary

This PR adds C as a generated output language. The main changes are:

  • Adds C to configuration, CLI selection, and language metadata.
  • Adds a libcurl and cJSON generation prompt.
  • Adds a compile-and-run command for generated C clients.
  • Adds documentation and focused prompt/helper tests.

Confidence Score: 4/5

C output cannot use the normal run-by-ID workflow, and dependency setup can produce unusable output or modify the host.

  • Script discovery still accepts only Python files.
  • The required cJSON sources are not supplied deterministically.
  • Missing curl headers can trigger a system package installation.

src/reverse_api/cli.py and src/reverse_api/prompts/partials/_language_c.md

Security Review

The C prompt can direct an automatically authorized agent to install host-level packages after a compile failure. System dependency installation should remain an explicit user-controlled step.

Important Files Changed

Filename Overview
src/reverse_api/base_engineer.py Adds C mappings, generated-file declarations, and an absolute-path compile-and-run command.
src/reverse_api/cli.py Adds C to settings, but the existing run-by-ID workflow cannot discover C output.
src/reverse_api/prompts/partials/_language_c.md Defines C generation, dependency, authentication, and testing instructions, with unresolved dependency-provisioning and host-installation behavior.
tests/test_base_engineer.py Tests the C extension, command string, and prompt assembly without exercising the complete run workflow.
tests/test_prompts.py Tests that the C partial renders, but not that its required dependencies are valid and available.
Prompt To Fix All With AI
Fix the following 3 code review issues. Work through them one at a time, proposing concise fixes.

---

### Issue 1 of 3
src/reverse_api/cli.py:1086
**C Runs Are Not Discoverable**

Selecting C creates `api_client.c`, but `reverse-api-engineer run <run_id>` still discovers only files with a `.py` suffix. A C-only run is therefore reported as having no scripts, so the normal run-by-ID workflow cannot execute the newly supported output.

### Issue 2 of 3
src/reverse_api/prompts/partials/_language_c.md:3
**Vendored Dependency Is Not Supplied**

The build command always requires `cJSON.c`, but the application does not provide a pinned cJSON source or a deterministic retrieval step. The agent must recreate or independently obtain the library, so a realistic generation can produce an incomplete or incompatible parser that fails to compile or behaves incorrectly at runtime.

### Issue 3 of 3
src/reverse_api/prompts/partials/_language_c.md:4
**Compile Failure Modifies The Host**

When the curl headers are missing, this instruction can make the automatically authorized agent install a system package. A privileged session is modified without a separate confirmation, while an unprivileged or unsupported environment exhausts generation retries and leaves the client unusable.

Reviews (1): Last reviewed commit: "Add C as a supported output language" | Re-trigger Greptile

Greptile also left 3 inline comments on this PR.

Follows the same overall pattern as python/javascript/typescript, but
C is genuinely different from every language added so far in two
ways, both addressed directly in the new partial
(prompts/partials/_language_c.md):

1. No stdlib HTTP or JSON. Unlike Go/PHP/Ruby (all fully
   dependency-free via their own standard libraries), C has neither.
   Uses libcurl for HTTP and vendors cJSON (a small, widely-used,
   permissively-licensed single-file JSON library) for JSON, rather
   than hand-rolling either - same reasoning as the Java PR's Gson
   choice: a real, tested library beats ad-hoc parsing written from
   scratch. libcurl itself is a system library a build step can't
   fetch, so the partial calls out installing it via the platform's
   package manager if the compiler can't find curl/curl.h.

2. Compiled, not run directly - the only such language here. Every
   other language's {run_command} is (or now points at) a single
   interpreter/build-tool invocation; C needs an explicit compile step
   first. _get_run_command() chains `cc <source> <cJSON.c> -lcurl -o
   <binary> && <binary>` as one command, using full paths throughout
   for the same reason already fixed on the Go/Java/C#/PHP/Ruby PRs -
   the agent's cwd is scripts_dir.parent.parent, not scripts_dir where
   everything is actually saved.

base_engineer.py: added "c" to _OUTPUT_LANGUAGE_EXTENSIONS (.c) and
_get_language_name() ("C"). _get_auto_output_files() always lists the
vendored cJSON.c/cJSON.h (not conditional - C always needs them, no
stdlib fallback, matching Java's always-included pom.xml rather than
javascript/go's conditional dependency files).

cli.py: added C to the interactive `output_language` config picker.
Updated the three docstrings/comments listing the language set
(config.py, engineer.py, prompts/__init__.py) and README.md's output
language line. Tests mirror the existing per-language pattern in both
test_base_engineer.py and test_prompts.py.

Checked for the literal-brace str.format_map() bug caught in the Java
PR - no literal `{`/`}` anywhere in the new partial.

Full test suite passes (49/49, run 3x) except the same pre-existing
flaky test noted on the other language PRs. ruff check clean on every
file this touches (8 pre-existing lint errors elsewhere on main, none
in the touched lines).
Comment thread src/reverse_api/cli.py
Choice(title="python", value="python"),
Choice(title="javascript", value="javascript"),
Choice(title="typescript", value="typescript"),
Choice(title="c", value="c"),

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

P1 C Runs Are Not Discoverable

Selecting C creates api_client.c, but reverse-api-engineer run <run_id> still discovers only files with a .py suffix. A C-only run is therefore reported as having no scripts, so the normal run-by-ID workflow cannot execute the newly supported output.

Prompt To Fix With AI
This is a comment left during a code review.
Path: src/reverse_api/cli.py
Line: 1086

Comment:
**C Runs Are Not Discoverable**

Selecting C creates `api_client.c`, but `reverse-api-engineer run <run_id>` still discovers only files with a `.py` suffix. A C-only run is therefore reported as having no scripts, so the normal run-by-ID workflow cannot execute the newly supported output.

How can I resolve this? If you propose a fix, please make it concise.

@@ -0,0 +1,23 @@
**Generate a C program** that replicates the API calls found in the traffic. The following are guidelines — use your judgment on what's appropriate for the specific API:

- C has no HTTP client or JSON support in its standard library, unlike every other output language here — use `libcurl` for requests and vendor `cJSON` (a small, widely-used, permissively-licensed single-file JSON library — `cJSON.c`/`cJSON.h`) for JSON, rather than hand-rolling either from scratch

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

P1 Vendored Dependency Is Not Supplied

The build command always requires cJSON.c, but the application does not provide a pinned cJSON source or a deterministic retrieval step. The agent must recreate or independently obtain the library, so a realistic generation can produce an incomplete or incompatible parser that fails to compile or behaves incorrectly at runtime.

Prompt To Fix With AI
This is a comment left during a code review.
Path: src/reverse_api/prompts/partials/_language_c.md
Line: 3

Comment:
**Vendored Dependency Is Not Supplied**

The build command always requires `cJSON.c`, but the application does not provide a pinned cJSON source or a deterministic retrieval step. The agent must recreate or independently obtain the library, so a realistic generation can produce an incomplete or incompatible parser that fails to compile or behaves incorrectly at runtime.

How can I resolve this? If you propose a fix, please make it concise.

**Generate a C program** that replicates the API calls found in the traffic. The following are guidelines — use your judgment on what's appropriate for the specific API:

- C has no HTTP client or JSON support in its standard library, unlike every other output language here — use `libcurl` for requests and vendor `cJSON` (a small, widely-used, permissively-licensed single-file JSON library — `cJSON.c`/`cJSON.h`) for JSON, rather than hand-rolling either from scratch
- `libcurl` itself is a system library, not something a build step can fetch — if compilation fails because `curl/curl.h` isn't found, install it with whatever package manager is available (e.g. `apt-get install -y libcurl4-openssl-dev`, `brew install curl`) before retrying

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

P1 security Compile Failure Modifies The Host

When the curl headers are missing, this instruction can make the automatically authorized agent install a system package. A privileged session is modified without a separate confirmation, while an unprivileged or unsupported environment exhausts generation retries and leaves the client unusable.

Prompt To Fix With AI
This is a comment left during a code review.
Path: src/reverse_api/prompts/partials/_language_c.md
Line: 4

Comment:
**Compile Failure Modifies The Host**

When the curl headers are missing, this instruction can make the automatically authorized agent install a system package. A privileged session is modified without a separate confirmation, while an unprivileged or unsupported environment exhausts generation retries and leaves the client unusable.

How can I resolve this? If you propose a fix, please make it concise.

@kind-agent

kind-agent Bot commented Jul 21, 2026

Copy link
Copy Markdown

⚠️ Error — The test run failed unexpectedly.

Snapshot kind-sandbox is inactive

This is likely a transient issue. You can re-trigger a run from the dashboard.

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

2 issues found across 10 files

Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name="src/reverse_api/base_engineer.py">

<violation number="1" location="src/reverse_api/base_engineer.py:478">
P2: The C run command always compiles `cJSON.c`, but this change set does not ship a pinned cJSON source artifact or deterministic retrieval path. That makes C execution depend on model-generated library code, which can be incomplete or incompatible and lead to compile/runtime failures; consider bundling a pinned vendored cJSON copy and compiling against that file.</violation>
</file>

<file name="src/reverse_api/cli.py">

<violation number="1" location="src/reverse_api/cli.py:1086">
P1: Adding `c` to the output-language picker exposes a path where `reverse-api-engineer run <run_id>` can’t execute C-only outputs if run discovery still filters to `.py` files. It would help to wire C into run-file discovery so the standard run-by-ID workflow works for the new language.</violation>
</file>

Reply with feedback, questions, or to request a fix.

Re-trigger cubic

Comment thread src/reverse_api/base_engineer.py Outdated
Comment thread src/reverse_api/prompts/partials/_language_c.md Outdated
Comment thread src/reverse_api/cli.py
Choice(title="python", value="python"),
Choice(title="javascript", value="javascript"),
Choice(title="typescript", value="typescript"),
Choice(title="c", value="c"),

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

P1: Adding c to the output-language picker exposes a path where reverse-api-engineer run <run_id> can’t execute C-only outputs if run discovery still filters to .py files. It would help to wire C into run-file discovery so the standard run-by-ID workflow works for the new language.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At src/reverse_api/cli.py, line 1086:

<comment>Adding `c` to the output-language picker exposes a path where `reverse-api-engineer run <run_id>` can’t execute C-only outputs if run discovery still filters to `.py` files. It would help to wire C into run-file discovery so the standard run-by-ID workflow works for the new language.</comment>

<file context>
@@ -1083,6 +1083,7 @@ def handle_settings(mode_color=THEME_PRIMARY):
             Choice(title="python", value="python"),
             Choice(title="javascript", value="javascript"),
             Choice(title="typescript", value="typescript"),
+            Choice(title="c", value="c"),
             Choice(title="back", value="back"),
         ]
</file context>

Comment thread src/reverse_api/base_engineer.py Outdated
source = f"{self.scripts_dir}/{self._get_client_filename()}"
cjson = f"{self.scripts_dir}/cJSON.c"
binary = f"{self.scripts_dir}/api_client"
return f'cc "{source}" "{cjson}" -lcurl -o "{binary}" && "{binary}"'

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

P2: The C run command always compiles cJSON.c, but this change set does not ship a pinned cJSON source artifact or deterministic retrieval path. That makes C execution depend on model-generated library code, which can be incomplete or incompatible and lead to compile/runtime failures; consider bundling a pinned vendored cJSON copy and compiling against that file.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At src/reverse_api/base_engineer.py, line 478:

<comment>The C run command always compiles `cJSON.c`, but this change set does not ship a pinned cJSON source artifact or deterministic retrieval path. That makes C execution depend on model-generated library code, which can be incomplete or incompatible and lead to compile/runtime failures; consider bundling a pinned vendored cJSON copy and compiling against that file.</comment>

<file context>
@@ -463,6 +465,17 @@ def _get_client_filename(self) -> str:
+            source = f"{self.scripts_dir}/{self._get_client_filename()}"
+            cjson = f"{self.scripts_dir}/cJSON.c"
+            binary = f"{self.scripts_dir}/api_client"
+            return f'cc "{source}" "{cjson}" -lcurl -o "{binary}" && "{binary}"'
         return {
             "python": "python api_client.py",
</file context>

Joshua Dunbar added 3 commits July 21, 2026 15:55
Manually double-quoting each path (f'cc "{source}" "{cjson}" ... "{binary}"')
does not stop $()/backtick command substitution inside a POSIX shell
double-quoted string. Use shlex.quote() on all three paths (source,
vendored cJSON, compiled binary) instead, matching the fix already
applied to the Go/Java/C#/PHP/Ruby run commands after bot review
flagged the same issue on the PHP PR.
… host

Both review bots independently flagged two real issues in the C partial:

- The instruction to "vendor cJSON" gave no deterministic retrieval step,
  so the agent had to reconstruct the library from memory, risking an
  incomplete or subtly wrong JSON parser. Now fetches the exact pinned
  upstream source (cJSON v1.7.18) via curl instead.
- Telling the agent to run apt-get/brew itself when libcurl headers are
  missing lets an auto-authorized session modify the host without a
  separate confirmation. Now it stops and reports a clear prerequisite
  error instead, leaving the actual install to the user.

Also investigated a third finding from both bots: `reverse-api-engineer
run <run_id>` only discovers `.py` files (utils.py's discover_scripts),
so a C-only run can't be executed via that subcommand. Confirmed this
predates this PR — JS/TS output has the same gap already, and the run
subcommand's execution path (venv creation, pip install, ModuleNotFoundError-
driven dependency retry) is Python-specific throughout, not just a filename
filter. Fixing it means designing a per-language execution/dependency-
retry story, which is a cross-cutting feature beyond a single-language
addition. Not fixed here, same reasoning as the Java/C# PRs.
Same root cause cubic flagged on the C# and Ruby PRs: a relative
--output-dir leaves scripts_dir relative to the original cwd, but once
the agent's cwd moves to scripts_dir.parent.parent (see
analyze_and_generate), embedding that same relative string re-interprets
it from the new location and points all three paths (source, vendored
cJSON, compiled binary) at the wrong, doubly-nested location. Resolve
scripts_dir once before deriving all three paths, proactively applying
the same fix here before it gets flagged.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant