Skip to content
Open
4 changes: 4 additions & 0 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,10 @@ uv run forge worker

# Print Forge version
uv run forge version
uv run forge version --json

# Run Forge as a module
python -m forge version

# Build container
podman build -t forge-dev:latest containers/
Expand Down
20 changes: 17 additions & 3 deletions docs/developer-guide.md
Original file line number Diff line number Diff line change
Expand Up @@ -723,17 +723,31 @@ For workflows paused at `review_response_gate` (due to contested comments):

### Forge Version Command

To print the currently installed Forge package version, run:
To print the currently installed Forge package version in plain text, run:

```bash
uv run forge version
```

This will print the package version in the format `Forge v<version>` (e.g., `Forge v1.0.0`) and exit with a success status code.
This will print the package version in the format `Forge v<version>` (e.g., `Forge v2.0.0`) and exit with a success status code.

To print the version information as a JSON object, run:

```bash
uv run forge version --json
```

This will print the version metadata in compact JSON format (e.g., `{"version": "2.0.0"}`) directly to standard output.

Alternatively, you can run Forge as a module using the `python -m` option:

```bash
python -m forge version
```

### Worker logs

The worker logs to stdout. Useful log entries to grep for:
The worker logs strictly to stderr to prevent log messages from polluting standard output. Useful log entries to grep for:

```bash
# Watch for a specific ticket
Expand Down
8 changes: 8 additions & 0 deletions src/forge/__main__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
"""Main entry point for forge when run as a module."""

import sys

from forge.cli import main

if __name__ == "__main__":
sys.exit(main())
47 changes: 40 additions & 7 deletions src/forge/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,34 @@

def setup_logging(verbose: bool = False) -> None:
"""Configure logging for CLI usage."""
root_logger = logging.getLogger()
# Clear any pre-existing logging handlers registered on the root logger
for handler in list(root_logger.handlers):
root_logger.removeHandler(handler)

level = logging.DEBUG if verbose else logging.INFO
logging.basicConfig(
level=level,
format="%(asctime)s - %(name)s - %(levelname)s - %(message)s",
)
root_logger.setLevel(level)

# Instantiate and attach a new logging.StreamHandler(sys.stderr)
handler = logging.StreamHandler(sys.stderr)
handler.setLevel(level)

formatter = logging.Formatter("%(asctime)s - %(name)s - %(levelname)s - %(message)s")
handler.setFormatter(formatter)

root_logger.addHandler(handler)

# Ensure all auxiliary loggers and standard console handlers default strictly to stderr
for logger_obj in list(logging.root.manager.loggerDict.values()):
if isinstance(logger_obj, logging.Logger):
for h in list(logger_obj.handlers):
if isinstance(h, logging.StreamHandler) and (
h.stream is sys.stdout or h.stream == sys.stdout
):
if logger_obj.propagate:
logger_obj.removeHandler(h)
else:
h.stream = sys.stderr


async def _get_compiled_workflow_for_ticket(ticket_key: str):
Expand Down Expand Up @@ -1423,11 +1446,16 @@ async def cmd_smoke_test(_args: argparse.Namespace) -> int:
return await run_smoke_test(settings)


async def cmd_version(_args: argparse.Namespace) -> int:
async def cmd_version(args: argparse.Namespace) -> int:
"""Print the installed Forge package version."""
from forge import __version__

print(f"Forge v{__version__}")
if getattr(args, "json", False):
import json

print(json.dumps({"version": __version__}))
else:
print(f"Forge v{__version__}")
return 0


Expand Down Expand Up @@ -1553,10 +1581,15 @@ def main(argv: list[str] | None = None) -> int:
)

# version command
subparsers.add_parser(
version_parser = subparsers.add_parser(
"version",
help="Print the installed Forge package version",
)
version_parser.add_argument(
"--json",
action="store_true",
help="Print version information as a JSON object",
)

# test-skill subparser group
test_skill_parser = subparsers.add_parser(
Expand Down
Loading
Loading