{"id":26511262,"url":"https://github.com/myfavshrimp/arc","last_synced_at":"2026-05-06T22:33:41.374Z","repository":{"id":282938819,"uuid":"949575877","full_name":"myFavShrimp/arc","owner":"myFavShrimp","description":"An automation tool that uses Lua for scripting.","archived":false,"fork":false,"pushed_at":"2026-03-13T19:19:32.000Z","size":359,"stargazers_count":1,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2026-03-14T07:40:24.337Z","etag":null,"topics":["automation","cli","infrastructure","infrastructure-as-code","lua","luau","rust"],"latest_commit_sha":null,"homepage":"","language":"Rust","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/myFavShrimp.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2025-03-16T18:56:03.000Z","updated_at":"2026-03-13T19:19:37.000Z","dependencies_parsed_at":"2025-03-17T19:29:58.094Z","dependency_job_id":"441044e4-ecb1-4e7b-8442-dc2fa74d963f","html_url":"https://github.com/myFavShrimp/arc","commit_stats":null,"previous_names":["myfavshrimp/arc"],"tags_count":1,"template":false,"template_full_name":null,"purl":"pkg:github/myFavShrimp/arc","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/myFavShrimp%2Farc","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/myFavShrimp%2Farc/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/myFavShrimp%2Farc/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/myFavShrimp%2Farc/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/myFavShrimp","download_url":"https://codeload.github.com/myFavShrimp/arc/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/myFavShrimp%2Farc/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":32714970,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-06T19:35:05.142Z","status":"ssl_error","status_checked_at":"2026-05-06T19:35:03.996Z","response_time":117,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["automation","cli","infrastructure","infrastructure-as-code","lua","luau","rust"],"created_at":"2025-03-21T02:31:22.497Z","updated_at":"2026-05-06T22:33:41.361Z","avatar_url":"https://github.com/myFavShrimp.png","language":"Rust","funding_links":[],"categories":[],"sub_categories":[],"readme":"# arc\n\narc (Automatic Remote Controller) is a general-purpose automation tool that uses Lua for scripting. It executes tasks on the local or remote systems via SSH with a flexible API for managing configurations, files, and commands across multiple servers. arc is not limited to a single domain and can be used as a build tool, for CI/CD, infrastructure provisioning, deployment, and many more, all within a single project sharing the same logic.\n\n[![asciicast](https://asciinema.org/a/L5fJR5JOLVziZyvA.svg)](https://asciinema.org/a/L5fJR5JOLVziZyvA)\n\n## Installation\n\n### Pre-built binaries\n\nPre-built binaries are available on the [GitHub releases page](https://github.com/myFavShrimp/arc/releases).\n\nAlternatively, using [cargo-binstall](https://github.com/cargo-bins/cargo-binstall):\n\n```bash\ncargo binstall arc-automation\n```\n\n### From source\n\n1. Install [Rust](https://rust-lang.org/)\n\n2. Install arc using Cargo:\n\n```bash\ncargo install arc-automation\n```\n\nThis will compile and install the `arc` binary to the Cargo bin directory (usually `~/.cargo/bin/`).\n\nPlease make sure you have the required dependencies installed:\n\n**Fedora**\n\n```bash\nsudo dnf group install development-tools\nsudo dnf install openssl-devel\n```\n\n**Ubuntu / Debian**\n\n```bash\nsudo apt install build-essential libssl-dev\n```\n\n**MacOS**\n\n- Install [Homebrew](https://brew.sh/)\n\n```bash\nbrew install openssl\n```\n\n## Quick Start\n\n### Creating a New Project\n\nInitialize a new arc project with type definitions for LSP support:\n\n```bash\narc init /path/to/project\n```\n\nThis command creates the project structure, type definitions for code completion and type checking, and a basic `arc.lua` file with example tasks.\n\n### Minimal Example\n\n```lua\n-- Define a target system\ntargets.systems[\"web-server\"] = {\n    address = \"192.168.1.100\",\n    user = \"root\",\n}\n\n-- Define a simple task\ntasks[\"hello\"] = {\n    handler = function(system)\n        local result = system:run_command(\"echo 'Hello from ' $(hostname)\")\n        print(result.stdout)\n    end\n}\n```\n\nRun the task:\n\n```bash\narc run -s web-server -t hello\n```\n\nSee the [examples](examples/) directory for more complete usage examples. You can also explore the available commands using `arc --help`, `arc run --help` etc.\n\n## Core Concepts\n\n### Targets\n\nTargets define the systems where tasks will be executed. There are two types: individual systems and groups.\n\n#### Systems\n\nSystems can be either remote (accessed via SSH) or local (running on the arc host machine).\n\n##### Remote Systems\n\nRemote systems represent individual servers with SSH connection details.\n\n```lua\ntargets.systems[\"frontend-server\"] = {\n    address = \"192.168.1.100\",\n    user = \"root\",\n    port = 22,  -- optional, defaults to 22\n}\n\ntargets.systems[\"api-server\"] = {\n    address = \"192.168.1.101\",\n    user = \"deploy\",\n    port = 2222,\n}\n```\n\nAuthentication is handled through the SSH agent. The host's public key must be present in the remote server's `authorized_keys`.\n\n##### Local Systems\n\nLocal systems execute tasks on the machine where arc is running.\n\n```lua\ntargets.systems[\"localhost\"] = {\n    type = \"local\"\n}\n```\n\nLocal systems use the same API as remote systems but operations execute locally instead of over SSH. The `address`, `port`, and `user` properties return `nil` for local systems.\n\n#### Groups\n\nGroups organize multiple systems.\n\n```lua\ntargets.groups[\"web-servers\"] = {\n    members = {\"frontend-server\", \"api-server\"}\n}\n\ntargets.groups[\"prod\"] = {\n    members = {\"prod-web-1\", \"prod-db-1\"}\n}\n```\n\n\n### Tasks\n\nTasks define operations to execute on target systems. Tasks execute in definition order on each system.\n\n```lua\ntasks[\"install_nginx\"] = {\n    handler = function(system)\n        local result = system:run_command(\"apt install nginx -y\")\n        if result.exit_code ~= 0 then\n            error(\"Failed to install nginx: \" .. result.stderr)\n        end\n    end,\n    tags = {\"nginx\", \"setup\"},\n}\n\ntasks[\"configure_nginx\"] = {\n    requires = {\"install_nginx\"},\n    handler = function(system)\n        local config = system:file(\"/etc/nginx/nginx.conf\")\n        config.content = \"...\"\n    end,\n    tags = {\"nginx\"},\n}\n```\n\nSee [Tasks API](#tasks-1) for all available fields.\n\n## Lua API Reference\n\narc uses a restricted [LuaJIT](https://luajit.org/) environment. The following standard library modules are available:\n\n- [Modules](https://www.lua.org/manual/5.1/manual.html#5.3) (`require`)\n- [String Manipulation](https://www.lua.org/manual/5.1/manual.html#5.4) (`string.format`, `string.match`, `string.gsub`, etc.)\n- [Table Manipulation](https://www.lua.org/manual/5.1/manual.html#5.5) (`table.insert`, `table.remove`, `table.sort`, etc.)\n- [Mathematical Functions](https://www.lua.org/manual/5.1/manual.html#5.6) (`math.floor`, `math.random`, etc.)\n\nNot available: `io`, `os`, `debug`, `coroutine`. Use the provided arc APIs (`system:run_command()`, `system:file()`, `env.get()`, etc.) instead.\n\nThe global `print()` function is an alias for `log.info()`.\n\n### Tasks\n\nTasks are defined by assigning to the global `tasks` table. Tasks execute in definition order on each system.\n\n#### Properties\n\n- `handler`: Function that implements the task logic\n  - *Parameters*: `system` - The system object to operate on\n  - *Returns*: Optional result value accessible via `tasks[\"name\"].result`\n\n- `tags` (optional): Array of tags for filtering tasks. Tasks are automatically tagged with their name and source file path components (e.g., `modules/web/nginx.lua` adds tags: `modules`, `web`, `nginx`).\n\n- `targets` (optional): Array of group or system names where this task should run. If omitted, runs on all systems.\n\n- `requires` (optional): Array of tags this task requires. Tasks with matching tags are included when this task is selected. Resolved transitively.\n\n- `when` (optional): Guard predicate that determines if the task should run\n  - *Returns*: `boolean` - If `false`, task is skipped\n\n- `on_fail` (optional): Behavior when this task fails\n  - `\"continue\"`: Proceed to next task\n  - `\"skip_system\"`: Skip remaining tasks for this system\n  - `\"abort\"` (default): Halt execution entirely\n\n- `important` (optional): If `true`, always runs regardless of tag filters, `--no-reqs`, and `skip_system`\n\n#### State (read-only, available after execution)\n\n- `result`: Return value from handler (nil if failed/skipped)\n- `state`: `\"success\"`, `\"failed\"`, or `\"skipped\"`\n- `error`: Error message if failed (nil otherwise)\n\nExample:\n\n```lua\ntasks[\"check_nginx\"] = {\n    handler = function(system)\n        return system:run_command(\"which nginx\").exit_code == 0\n    end\n}\n\ntasks[\"install_nginx\"] = {\n    requires = {\"check_nginx\"},\n    when = function()\n        return tasks[\"check_nginx\"].result == false\n    end,\n    handler = function(system)\n        local result = system:run_command(\"apt install nginx -y\")\n        if result.exit_code ~= 0 then\n            error(\"Failed: \" .. result.stderr)\n        end\n    end,\n    on_fail = \"skip_system\",\n}\n```\n\nRequires affect **which** tasks run, not **when**. Tasks always execute in definition order. If a task requires something defined later, the required task runs *after* the requiring task.\n\n### System Object\n\nThe `system` object represents a connection to a target system (remote or local) and is passed to task handlers.\n\n#### Properties\n\n- `name`: The name of the system as defined in `targets.systems`\n- `type`: The type of system - `\"remote\"` or `\"local\"`\n- `address`: The IP address of the system (nil for local systems)\n- `port`: The SSH port of the system (nil for local systems)\n- `user`: The SSH user used to connect to the system (nil for local systems)\n\n#### Methods\n\n- `run_command(cmd)`: Execute a command on the system\n  - *Parameters*: `cmd` (string) - The command to execute\n  - *Returns*: A table with `stdout`, `stderr`, and `exit_code`\n\n- `file(path)`: Get a File object representing a file on the system\n  - *Parameters*: `path` (string) - Path to the file\n  - *Returns*: A File object\n\n- `directory(path)`: Get a Directory object representing a directory on the system\n  - *Parameters*: `path` (string) - Path to the directory\n  - *Returns*: A Directory object\n\nExample:\n\n```lua\ntasks[\"check_service\"] = {\n    handler = function(system)\n        log.info(\"Checking nginx on \" .. system.name)\n        local result = system:run_command(\"systemctl status nginx\")\n        return result.exit_code == 0\n    end\n}\n```\n\n### File Object\n\nThe File object represents a file on a target system and provides access to file content, metadata, and operations.\n\n#### Properties\n\n- `path`: Path to the file (can be read and set; setting the path moves the file)\n- `file_name`: The name of the file without the directory path (can be read and set)\n- `content`: File content handle (can be read and set). Reading returns a `FileContent` object that acts as a lazy reference. Assigning a `FileContent` from one file to it transfers the data. The handle converts to a string automatically when used with `tostring()`, `..`, `print()`, `template.render()`, etc.\n- `permissions`: File permissions (can be read and set as numeric mode; returns `nil` if file doesn't exist)\n\n#### Methods\n\n- `exists()`: Check if file exists\n  - *Returns*: `boolean` - `true` if file exists, `false` otherwise\n\n- `metadata()`: Get file metadata\n  - *Returns*: A table with file metadata (see [Metadata Structure](#metadata-structure)), or `nil` if file doesn't exist\n\n- `remove()`: Remove the file\n\n- `directory()`: Get the directory containing this file\n  - *Returns*: A Directory object, or `nil` if at root path\n\nExample:\n\n```lua\ntasks[\"configure_nginx\"] = {\n    handler = function(system)\n        local config_file = system:file(\"/etc/nginx/sites-available/default\")\n\n        config_file.content = \"server {\\n    listen 80 default_server;\\n    root /var/www/html;\\n}\"\n        config_file.permissions = tonumber(\"644\", 8)\n\n        local metadata = config_file:metadata()\n\n        if metadata and metadata.size then\n            log.info(\"File size: \" .. metadata.size .. \" bytes\")\n        end\n    end\n}\n\ntasks[\"manage_file\"] = {\n    handler = function(system)\n        -- Create, move and then delete a file\n        local file = system:file(\"/path/to/file.txt\")\n        file.content = \"New content\"                 -- Write to file\n        file.permissions = tonumber(\"755\", 8)        -- Set permissions\n        file.path = \"/new-path/to/renamed-file.txt\"  -- Rename file\n        file:remove()                                -- Delete file\n    end\n}\n```\n\n### Directory Object\n\nThe Directory object represents a directory on a target system and provides access to directory operations and contents.\n\n#### Properties\n\n- `path`: Path to the directory (can be read and set; setting the path renames the directory)\n- `file_name`: The name of the directory without the parent path (can be read and set)\n- `permissions`: Directory permissions (can be read and set as numeric mode; returns `nil` if directory doesn't exist)\n\n#### Methods\n\n- `create()`: Create the directory (including any missing ancestor directories)\n- `remove()`: Remove the directory\n- `exists()`: Check if directory exists\n  - *Returns*: `boolean` - `true` if directory exists, `false` otherwise\n- `metadata()`: Get directory metadata\n  - *Returns*: A table with directory metadata (see [Metadata Structure](#metadata-structure)), or `nil` if directory doesn't exist\n- `parent()`: Get the parent directory\n  - *Returns*: A Directory object representing the parent directory, or `nil` if at root path\n- `entries()`: Get directory entries\n  - *Returns*: Array of File and Directory objects representing the directory contents\n\nExample:\n\n```lua\ntasks[\"setup_directory\"] = {\n    handler = function(system)\n        -- Create directory structure\n        local app_dir = system:directory(\"/var/www/myapp\")\n        app_dir:create()\n\n        -- Set permissions\n        app_dir.permissions = tonumber(\"755\", 8)\n    end\n}\n\ntasks[\"list_configs\"] = {\n    handler = function(system)\n        -- Iterate through directory contents\n        local dir = system:directory(\"/etc/nginx/sites-available\")\n        for _, entry in ipairs(dir:entries()) do\n            -- Each entry is either a File or Directory object\n            local metadata = entry:metadata()\n\n            if metadata then\n                print(entry.path .. \" (\" .. metadata.type .. \")\")\n\n                if metadata.type == \"file\" and metadata.size then\n                    print(\"  Size: \" .. metadata.size .. \" bytes\")\n                end\n            end\n        end\n    end\n}\n\ntasks[\"manage_directory\"] = {\n    handler = function(system)\n        -- Create, move and then delete a directory\n        local dir = system:directory(\"/path/to/dir\")\n        dir:create()                                 -- Create directory\n        dir.path = \"/path/to/renamed-dir\"            -- Rename directory\n        dir:remove()                                 -- Delete directory\n    end\n}\n```\n\n### Metadata Structure\n\nThe `metadata()` method on File or Directory objects returns a table with the following fields, or `nil` if the file/directory doesn't exist:\n\n- `path`: Path to the file or directory\n- `size`: Size in bytes (number, or `nil` if unavailable)\n- `permissions`: Permission mode (number, or `nil` if unavailable)\n- `type`: Type of the item (\"file\", \"directory\", or \"unknown\")\n- `uid`: User ID of the owner (number, or `nil`; **always `nil` on local systems**)\n- `gid`: Group ID of the owner (number, or `nil`; **always `nil` on local systems**)\n- `accessed`: Last access time as a Unix timestamp (number, or `nil` if unavailable)\n- `modified`: Last modification time as a Unix timestamp (number, or `nil` if unavailable)\n\nExample:\n\n```lua\ntasks[\"check_metadata\"] = {\n    handler = function(system)\n        local file = system:file(\"/etc/hostname\")\n        local metadata = file:metadata()\n\n        if metadata then\n            log.info(\"File size: \" .. (metadata.size or \"unknown\"))\n            log.info(\"File type: \" .. metadata.type)\n            log.info(\"File permissions: \" .. (metadata.permissions or \"unknown\"))\n            log.info(\"Last modified: \" .. (metadata.modified or \"unknown\"))\n        else\n            log.info(\"File does not exist\")\n        end\n    end\n}\n```\n\n### Environment Variables (env)\n\nThe `env` module provides access to environment variables. arc automatically loads variables from `.env` files in the project directory. Variables defined in the `.env` file take precedence over already defined ones.\n\n#### Methods\n\n- `get(var_name)`: Get the value of an environment variable\n  - *Parameters*: `var_name` (string) - Name of the environment variable\n  - *Returns*: Value of the environment variable (string) or nil if not set\n\nExample:\n\n```lua\ntasks[\"deploy_app\"] = {\n    handler = function(system)\n        local app_version = env.get(\"APP_VERSION\") or \"latest\"\n        local deploy_path = env.get(\"DEPLOY_PATH\") or \"/var/www\"\n\n        system:run_command(\"docker pull myapp:\" .. app_version)\n        system:run_command(\"docker run -d -v \" .. deploy_path .. \":/app myapp:\" .. app_version)\n    end\n}\n```\n\n### Host Object\n\nThe global `host` object provides functions for interacting with the local system where arc is running. It has the same interface as the `system` object but operates on the local machine and its working directory is the directory where `arc.lua` is located.\n\n#### Methods\n\n- `run_command(cmd)`: Execute a command on the local system\n  - *Parameters*: `cmd` (string) - The command to execute\n  - *Returns*: A table with `stdout`, `stderr`, and `exit_code`\n\n- `file(path)`: Get a File object representing a file on the local system\n  - *Parameters*: `path` (string) - Path to the file\n  - *Returns*: A File object\n\n- `directory(path)`: Get a Directory object representing a directory on the local system\n  - *Parameters*: `path` (string) - Path to the directory\n  - *Returns*: A Directory object\n\nExample:\n\n```lua\ntasks[\"deploy_from_local\"] = {\n    handler = function(system)\n        -- Streams the file directly from local to remote without loading it into memory\n        system:file(\"/etc/nginx/nginx.conf\").content = host:file(\"templates/nginx.conf\").content\n\n        -- Restart service\n        system:run_command(\"systemctl restart nginx\")\n    end\n}\n\ntasks[\"backup_to_local\"] = {\n    handler = function(system)\n        -- Streams from remote to local\n        local backup_dir = host:directory(\"backups/\" .. system.name)\n        backup_dir:create()\n\n        host:file(\"backups/\" .. system.name .. \"/config.json\").content =\n            system:file(\"/etc/app/config.json\").content\n    end\n}\n```\n\n### Format Module\n\nThe `format` module provides serialization and deserialization for various data formats. Each format is accessible as a sub-module.\n\nExample:\n\n```lua\ntasks[\"edit_config\"] = {\n    handler = function(system)\n        -- Decode a JSON config, modify it, and write it back\n        local config_file = system:file(\"/etc/myapp/config.json\")\n        local config = format.json.decode(config_file.content)\n\n        config.debug = true\n        config.log_level = \"info\"\n\n        config_file.content = format.json.encode_pretty(config)\n    end\n}\n```\n\n#### `format.json`\n\n- `encode(value)`: Serializes a Lua value as a JSON string\n  - *Parameters*: `value` (any) - The Lua value to serialize\n  - *Returns*: JSON string\n\n- `encode_pretty(value)`: Serializes a Lua value as a pretty-printed JSON string\n  - *Parameters*: `value` (any) - The Lua value to serialize\n  - *Returns*: Pretty-printed JSON string\n\n- `decode(input)`: Deserializes a JSON string to a Lua value\n  - *Parameters*: `input` (string | file content) - JSON string to deserialize\n  - *Returns*: Decoded Lua value\n\n#### `format.toml`\n\n- `encode(value)`: Serializes a Lua value as a TOML string\n  - *Parameters*: `value` (any) - The Lua value to serialize\n  - *Returns*: TOML string\n\n- `decode(input)`: Deserializes a TOML string to a Lua value\n  - *Parameters*: `input` (string | file content) - TOML string to deserialize\n  - *Returns*: Decoded Lua value\n\n#### `format.yaml`\n\n- `encode(value)`: Serializes a Lua value as a YAML string\n  - *Parameters*: `value` (any) - The Lua value to serialize\n  - *Returns*: YAML string\n\n- `decode(input)`: Deserializes a YAML string to a Lua value\n  - *Parameters*: `input` (string | file content) - YAML string to deserialize\n  - *Returns*: Decoded Lua value\n\n#### `format.url`\n\n- `encode(value)`: Serializes a Lua value as a URL query string\n  - *Parameters*: `value` (any) - The Lua value to serialize\n  - *Returns*: URL-encoded query string (`x-www-form-urlencoded`)\n\n- `decode(input)`: Deserializes a URL query string to a Lua value\n  - *Parameters*: `input` (string | file content) - URL query string to deserialize\n  - *Returns*: Decoded Lua value\n\n#### `format.env`\n\n- `decode(input)`: Deserializes dotenv-formatted `KEY=VALUE` lines to a table\n  - *Parameters*: `input` (string | file content) - Dotenv string to deserialize\n  - *Returns*: Table of key-value string pairs\n\n### Template Module\n\nThe `template` module provides template rendering capabilities using the [Tera](https://keats.github.io/tera/docs/#templates) template engine.\n\n#### Methods\n\n- `render(template_content, context)`: Render a template with given context\n  - *Parameters*:\n    - `template_content` (string | file content) - Template content\n    - `context` (table) - Variables to use for template rendering\n  - *Returns*: Rendered template as string\n\nExample:\n\n```lua\ntasks[\"configure_web_server\"] = {\n    handler = function(system)\n        -- Load a template from a local file\n        local template_content = host:file(\"templates/nginx.conf.template\").content\n\n        -- Define context variables\n        local context = {\n            worker_processes = 4,\n            worker_connections = 1024,\n            server_name = system.name .. \".example.com\",\n            document_root = \"/var/www/\" .. system.name,\n            environment = env.get(\"ENVIRONMENT\") or \"production\"\n        }\n\n        -- Render and deploy configuration\n        local config = template.render(template_content, context)\n        system:file(\"/etc/nginx/nginx.conf\").content = config\n\n        -- Validate and reload\n        local validation = system:run_command(\"nginx -t\")\n\n        if validation.exit_code == 0 then\n            system:run_command(\"systemctl reload nginx\")\n        else\n            error(\"Nginx configuration is invalid: \" .. validation.stderr)\n        end\n    end\n}\n```\n\n### Arc Module\n\nThe global `arc` object provides information about the arc project and environment.\n\n#### Properties\n\n- `project_root_path`: The absolute path to the project root directory (where `arc.lua` is located)\n- `home_path`: The absolute path to the user's home directory\n\nExample:\n\n```lua\ntasks[\"deploy_config\"] = {\n    handler = function(system)\n        -- Read a file relative to the project root\n        local config = host:file(arc.project_root_path .. \"/configs/app.json\").content\n        system:file(\"/etc/myapp/config.json\").content = config\n    end\n}\n```\n\n### Logging Module\n\nThe `log` module provides logging functions at various severity levels.\n\n#### Functions\n\n- `debug(value)`: Log a debug message\n  - *Parameters*: `value` (any) - Value to log\n\n- `info(value)`: Log an info message\n  - *Parameters*: `value` (any) - Value to log\n\n- `warn(value)`: Log a warning message\n  - *Parameters*: `value` (any) - Value to log\n\n- `error(value)`: Log an error message\n  - *Parameters*: `value` (any) - Value to log\n\nExample:\n\n```lua\ntasks[\"provision_database\"] = {\n    handler = function(system)\n        log.info(\"Provisioning database on \" .. system.name)\n\n        local check = system:run_command(\"which psql\")\n        log.debug(\"which psql exit code: \" .. check.exit_code)\n\n        if check.exit_code ~= 0 then\n            log.warn(\"PostgreSQL not found, attempting to install\")\n\n            local install_result = system:run_command(\"apt-get install -y postgresql\")\n            if install_result.exit_code ~= 0 then\n                error(\"Failed to install PostgreSQL: \" .. install_result.stderr)\n            end\n        end\n\n        log.info(\"PostgreSQL is available\")\n    end\n}\n```\n\n## LSP Support\n\narc provides Language Server Protocol (LSP) support for Lua code editing with autocomplete, type checking, and inline documentation.\n\n### Setup\n\n1. Install the [Lua Language Server](https://github.com/LuaLS/lua-language-server) for the editor being used.\n\n2. Initialize an arc project to generate type definitions:\n\n```bash\narc init /path/to/project\n```\n\nThe `init` command creates `.luarc.json` and type definition files that enable the Lua Language Server to recognize arc's API types.\n\n## Contributing\n\nContributions are welcome! Please feel free to submit any issue or pull request.\n\n## License\n\nThis project is licensed under the MIT License - see the LICENSE file for details.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmyfavshrimp%2Farc","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmyfavshrimp%2Farc","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmyfavshrimp%2Farc/lists"}