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
14 changes: 12 additions & 2 deletions .github/dependabot.yml
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,18 @@ updates:
patterns:
- "*"

- package-ecosystem: "pip" # See documentation for possible values
directory: "./" # Location of package manifests
- package-ecosystem: "pip"
directory: "/pkg"
schedule:
interval: "weekly"
day: "sunday"
groups:
all-pip:
patterns:
- "*"

- package-ecosystem: "pip"
directory: "/src"
schedule:
interval: "weekly"
day: "sunday"
Expand Down
125 changes: 125 additions & 0 deletions AGENTS.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
# Aloha — Contributor Guidelines

Welcome, AI Coding Agents (`agy`, `Claude Code`, `GitHub Copilot`, etc.)! This document serves as your central instruction entry point. Please read this file and the referenced skills before making any modifications to the codebase.

## 1. Project Context

`aloha-python` is a modern project template (boilerplate) and a versatile utility library (`aloha` package) designed to build robust, containerized microservices in Python.

### Repository Structure

- `src/`: Application-specific codebase, configuration resources, and tests.
- `src/resource/config/`: Configuration files (`main.conf`, settings, profiles).
- `src/tests/`: Unit and integration tests.
- `pkg/`: Core `aloha` utility library package source code.
- `tool/`: Helper scripts, build files, and Docker/Docker Compose configs for local CI/CD.
- `doc/`: Documentation files and AI Agent Skills.
- `doc/skill`: The folder to store all project skill files -- all other agent-specific skill folders (e.g.: `.claude/skills`, `.agent/skills`) point to this folder using symlinks.
- `notebook/`: Jupyter notebooks for interactive analysis.
- `.agents/`: Local customization folder for AI agents containing the `skills` symlink setup.

## 2. Working Rules

When writing code or configurations for this project, you **MUST** strictly adhere to the following rules:

### A. Python Coding & Naming Standards

- **Primary Type/First-Class Identity Prefix**: Place the variable's type, role, or primary characteristics first in its name.
- _Correct_: `name_service`, `port_service`, `svc_ingress`, `cfg_postgres`, `db_mysql`.
- _Incorrect_: `service_name`, `service_port`, `ingress_service`, `postgres_config`, `mysql_db`.
- **Logger Naming**: Use lowercase with underscores for logger names, e.g., `db_sync`, `api_router`.
- **Import Conventions**: Use relative imports if possible, especially inside a package.

### B. Configuration & Security

- **HOCON Configuration**: Always use HOCON configuration via `aloha.config` (`SETTINGS` object). Maintain configurations in modular files and import them using the HOCON `include` directive in `main.conf`.
- **No Hardcoded Credentials**: Never write plaintext passwords or secrets in configuration files. Configure secrets to resolve dynamically at runtime using the `PasswordVault`.

### C. Logging & Concurrency

- **Safe Multi-Process Logging**: Do not instantiate default Python `FileHandler` inside concurrent or multi-process tasks. Use `aloha.logger.LOG` or named loggers from `get_logger()` to ensure safe concurrent log writing.

### D. Testing Guidelines

- **Framework**: Use `pytest` for all unit and integration testing.
- **Harness**: Subclass `UnitTestCase` or `ServiceTestCase` from `aloha.testing` to leverage pre-configured settings, DB connections, and loggers.

## 3. Skills

We have defined explicit skills to guide specific development tasks. Refer to the corresponding instruction files before editing relevant code:

- **[Aloha Python Skill](doc/skills/aloha_python/SKILL.md)**
- Covers Python naming standards, sub-modules usage (`aloha.config`, `aloha.logger`, `aloha.encrypt`, `aloha.db`, `aloha.testing`), and the Cython binary compilation process.
- **[Aloha CI/CD & Scaffolding Skill](doc/skills/aloha_cicd/SKILL.md)**
- Covers project structure layout, local containerized development environments via `./tool/cicd/run-dev.sh`, user-specific port calculations, and production Docker builds.

## 4. Runtime Environment

Note: It is always advised to develop/debug/test code inside a container environment by using the method specified in `Local Container Lifecycle`.

To execute scripts, run tests, or compile code, work within the containerized local development environment:

### A. Local Container Lifecycle

Management is driven by `./tool/cicd/run-dev.sh`:

```bash
# Start the development container in the background
./tool/cicd/run-dev.sh up

# Open an interactive shell inside the container
./tool/cicd/run-dev.sh enter

# Stop the development container
./tool/cicd/run-dev.sh down
```

> [!NOTE]
> The helper script dynamically assigns `PORT_APP` and `PORT_WEB` based on your system `UID` to prevent port collisions on shared servers.

### B. Module Execution

To run application entry points, use the generic module runner:

```bash
cd src

# Execute within the dev container
python3 main.py <module_path>.<function_name>

# Example
python3 main.py app_common.main
```

### C. Running Tests

Run tests from the root directory _inside the container terminal_:

```bash
cd src

# Run pytest on application source code
pytest ./

# Run tests and output test coverage
pytest --cov=./ ./
```

### D. Binary Compilation & Packaging

To compile code using Cython and build production images:

```bash
# Source tool utilities and build the Docker image
source tool/tool.sh
build_image app_common latest src/app-demo.Dockerfile
```

## 5. Extension Metadata

This configuration allows AI coding assistants to load this project's custom definitions automatically.

### Agent Skill Mapping

- **Config file**: `.agents/skills`
- **Path mapping**: Pointing to `../doc/skills`. Enables `codex`, `claude`, `agy`, etc. to resolve all workspace-scoped skills defined under `doc/skills/`.
76 changes: 61 additions & 15 deletions pkg/aloha/settings.py
Original file line number Diff line number Diff line change
@@ -1,42 +1,86 @@
from typing import Any

from attrdict import AttrDict

from .config import hocon, paths


class Settings:
"""
Global settings management class for aloha.
Global settings management class for the Aloha package.

Manages configuration loading and provides access to common directories.
This class manages the lazy loading of HOCON configuration files, environment
profile resolution, and provides access to project resource and configuration directories.

Attributes:
_config (Any | None): Internal storage for the parsed configuration.
"""

def __init__(self):
self._config = None
def __init__(self, config: Any | None = None):
"""
Initialize the Settings manager.

:param config: Optional pre-loaded configuration dictionary, list, or None.
If provided, it is parsed and loaded immediately.
"""
if config is None:
self._config = None
else:
self.load_settings(config)

@property
def resource_dir(self):
def dir_resource(self):
"""
Get the resource directory path.
Get the absolute path of the resource directory.

:return: Resource directory path
Resolves dynamically based on the `DIR_RESOURCE` environment variable,
falling back to the default 'resource' directory in the current working directory.

:return: Absolute path to the resource directory.
"""
return paths.get_resource_dir()

@property
def config_dir(self):
def dir_config(self):
"""
Get the configuration directory path.
Get the absolute path of the configuration directory.

Resolves dynamically based on the `DIR_CONFIG` environment variable,
falling back to the 'config' subdirectory under the resource directory.

:return: Config directory path
:return: Absolute path to the configuration directory.
"""
return paths.get_config_dir()

def load_settings(self, config: Any) -> Any:
"""
Recursively load and transform configuration values.

Converts raw dictionaries into `AttrDict` objects to support attribute-style
dot notation access, and recursively processes lists and nested values.

:param config: The configuration data to load (dict or list).
:return: The converted configuration object (AttrDict or list).
:raises ValueError: If the configuration data type is unsupported.
"""
if isinstance(config, dict):
self._config = AttrDict({key: self.load_settings(value) for key, value in config.items()})
elif isinstance(config, list):
self._config = [self.load_settings(value) for value in config]
else:
raise ValueError("Unsupported config type: %s" % str(type(config)))
return self._config

@property
def config(self):
"""
Get the global configuration object.

Lazily loads configuration from HOCON files on first access.
Lazily loads and parses configuration files on first access. It resolves active
HOCON configuration files based on the `FILES_CONFIG` or `ENV_PROFILE` environment
variables, falls back to `main.conf` if not specified, and merges them into an `AttrDict`.

:return: Configuration object
:return: Merged global configuration settings as an AttrDict.
"""
if self._config is None:
config_files = paths.get_config_files() # by default, use the `main.conf` file in the config_dir
Expand All @@ -46,10 +90,12 @@ def config(self):

def __getitem__(self, item):
"""
Get a configuration value by key.
Get a configuration value using dictionary key lookup syntax.

Allows retrieving configurations using `SETTINGS[key]`.

:param item: Configuration key
:return: Configuration value
:param item: The configuration key to look up.
:return: The resolved configuration value.
"""
return self.config[item]

Expand Down