Skip to content

Add Obsidian (with git sync), Eclipse Mosquitto, Gitea, ESPHome and MS SQL Server 2025 - #207

Merged
bubacoder merged 8 commits into
mainfrom
feature/new-services
Oct 13, 2025
Merged

Add Obsidian (with git sync), Eclipse Mosquitto, Gitea, ESPHome and MS SQL Server 2025#207
bubacoder merged 8 commits into
mainfrom
feature/new-services

Conversation

@bubacoder

@bubacoder bubacoder commented Oct 5, 2025

Copy link
Copy Markdown
Owner

Summary by CodeRabbit

  • New Features

    • Mosquitto MQTT service (proxy routing, WebSockets) and docs.
    • Obsidian container with vault mounting, backup/sync tasks.
    • ESPHome device builder, Gitea, and Microsoft SQL Server services.
    • CLI: new logs action with follow/tail/since/timestamps options.
    • Added services schema and new configuration keys for Obsidian, Gitea, MSSQL, and multiple cloud API tokens.
  • Chores

    • Replaced Olivetin with Mosquitto; deprecated Readarr.
    • Renamed example env task to update-example-env and added Obsidian Taskfile include; added backup task.
  • Documentation

    • Guides for Mosquitto, Obsidian, ESPHome, Gitea, MSSQL, and services schema; README/AGENTS task name updates.

@coderabbitai

coderabbitai Bot commented Oct 5, 2025

Copy link
Copy Markdown
Contributor

Walkthrough

Adds multiple new Docker service compose files and docs (Mosquitto, Obsidian, ESPHome device builder, Gitea, MSSQL), a services schema, Obsidian Taskfile for vault backup/sync, updates example env and task names (create→update), and extends the CLI with docker "logs" action and log-related flags.

Changes

Cohort / File(s) Summary of changes
Example env & services catalog
config-example/docker/myhost/.env, config-example/docker/myhost/services.yaml, config-example/docker/services-schema.yaml
Added STORAGE_OBSIDIAN and optional Obsidian auth envs; added Gitea/MSSQL and cloud/LLM API env keys; updated services catalog to include mosquitto, obsidian, esphome-device-builder, mssql-server, gitea; added services schema.
Mosquitto service
docker/automation/mosquitto.yaml, docker/automation/mosquitto/mosquitto.conf, docs/PRPs/containers/mosquitto.md
New Eclipse Mosquitto compose snippet (1883/8883/9001, persistence, logs, Traefik WS routing, external proxy network) plus static mosquitto.conf and deployment documentation.
Obsidian service & tasks
docker/tools/obsidian.yaml, docker/tools/Taskfile.obsidian.yaml, docs/PRPs/containers/obsidian.md
New Obsidian compose snippet (linuxserver/obsidian) with optional auth envs and vault mounts; Taskfile adds repo-sync, repo-commit, repo-backup to rsync and commit vault to Git; added docs.
ESPHome, Gitea, MSSQL services & docs
docker/automation/esphome-device-builder.yaml, docker/dev/gitea.yaml, docker/storage/mssql-server.yaml, docs/PRPs/containers/esphome-device-builder.md, docs/PRPs/containers/gitea.md, docs/PRPs/containers/mssql-server.md
Added compose snippets and docs for ESPHome device builder, Gitea (dev), and Microsoft SQL Server 2025 (service definitions, volumes, labels, networks).
Taskfiles & example env generation
Taskfile.yaml, docker/Taskfile.docker.yaml, scripts/update-example-env.py
Renamed task create-example-envupdate-example-env; switched invoked script to update-example-env.py; added include for Obsidian Taskfile; added public backup Taskfile task chaining backup-config + obsidian:repo-backup; copy/generate services-schema.yaml.
CLI tooling (logs) & scripting
scripts/labctl.py
Extended DockerOptions with log flags (follow, tail, since, timestamps); added build_log_command_flags; added 'logs' to ALLOWED_STATES; added support for logs action and propagated flags through the service CLI.
Docs & housekeeping
AGENTS.md, README.md, docker/guidelines.md, .pre-commit-config.yaml
Updated docs to reference docker:update-example-env; adjusted guidelines ordering/TODO; expanded EOF-fixer exclude regex to include mosquitto path and added minor wording updates.
Compose metadata & TODOs
docker/* (new service files), config-example/docker/myhost/*
Added homepage/metadata labels across new compose files and inserted TODO comments for TLS, backups, healthchecks, resource limits, and monitoring.

Sequence Diagram(s)

sequenceDiagram
  autonumber
  participant Client
  participant Traefik
  participant Obsidian as Obsidian:3000

  Client->>Traefik: GET obsidian.${MYDOMAIN}
  Traefik->>Obsidian: Route to container port 3000 (middleware: localaccess@file)
  Obsidian-->>Traefik: HTTP response
  Traefik-->>Client: Proxied response
  note right of Traefik: New service on external "proxy" network
Loading
sequenceDiagram
  autonumber
  participant MQTTClient as MQTT Client
  participant Traefik
  participant Mosquitto as Mosquitto:9001/1883

  MQTTClient->>Mosquitto: MQTT connect (1883)
  Mosquitto-->>MQTTClient: ConnAck / messages

  alt WebSocket via Traefik
    MQTTClient->>Traefik: WS to mosquitto.${MYDOMAIN}
    Traefik->>Mosquitto: Proxy to 9001 (websockets)
    Mosquitto-->>Traefik: WS frames
    Traefik-->>MQTTClient: Proxied WS frames
  end
  note right of Mosquitto: TLS/auth commented out / optional
Loading
sequenceDiagram
  autonumber
  participant Operator
  participant TaskRunner as Task
  participant Vault as Obsidian Vault
  participant Repo as Git Repo

  Operator->>TaskRunner: task backup
  TaskRunner->>TaskRunner: backup-config
  TaskRunner->>Vault: rsync (exclude .obsidian/)
  TaskRunner->>Repo: rsync -> repo (exclude .git/)
  TaskRunner->>Repo: git add --all
  TaskRunner->>Repo: git commit "Automatic sync" (if staged changes)
  TaskRunner-->>Operator: Backup complete
  note right of TaskRunner: Paths derived from STORAGE_OBSIDIAN and OBSIDIAN_VAULT_NAME
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

Pre-merge checks and finishing touches

✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title Check ✅ Passed The title clearly and specifically summarizes the primary additions of the pull request by listing the new services being introduced—Obsidian (with git sync), Eclipse Mosquitto, Gitea, ESPHome, and MS SQL Server 2025—matching the contents and objectives of the changeset. It is concise, focused on the main change, and would be immediately understandable to a teammate scanning the repository history.
Docstring Coverage ✅ Passed Docstring coverage is 85.71% which is sufficient. The required threshold is 80.00%.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch feature/new-services

📜 Recent review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between cbad2db and 6579fce.

📒 Files selected for processing (7)
  • .claude/commands/implement-container-deployment.md (1 hunks)
  • config-example/docker/myhost/.env (2 hunks)
  • config-example/docker/myhost/services.yaml (6 hunks)
  • docker/guidelines.md (2 hunks)
  • docker/storage/mssql-server.yaml (1 hunks)
  • docs/PRPs/containers/mssql-server.md (1 hunks)
  • scripts/labctl.py (5 hunks)
🚧 Files skipped from review as they are similar to previous changes (3)
  • docker/guidelines.md
  • .claude/commands/implement-container-deployment.md
  • docker/storage/mssql-server.yaml
🧰 Additional context used
📓 Path-based instructions (2)
**/*.{yml,yaml}

📄 CodeRabbit inference engine (AGENTS.md)

All YAML files must be linted and validated via pre-commit

Files:

  • config-example/docker/myhost/services.yaml
**/*.py

📄 CodeRabbit inference engine (AGENTS.md)

Python code must pass Ruff linting via pre-commit

Files:

  • scripts/labctl.py
🧠 Learnings (1)
📚 Learning: 2025-09-28T17:29:15.156Z
Learnt from: CR
PR: bubacoder/infra#0
File: AGENTS.md:0-0
Timestamp: 2025-09-28T17:29:15.156Z
Learning: Applies to config/docker/*/services.yaml : Add each service to the host-specific configuration at config/docker/<hostname>/services.yaml

Applied to files:

  • config-example/docker/myhost/services.yaml
🪛 dotenv-linter (3.3.0)
config-example/docker/myhost/.env

[warning] 12-12: [UnorderedKey] The STORAGE_OBSIDIAN key should go before the STORAGE_WEBDAV key

(UnorderedKey)


[warning] 101-101: [QuoteCharacter] The value has quote characters (', ")

(QuoteCharacter)


[warning] 103-103: [QuoteCharacter] The value has quote characters (', ")

(QuoteCharacter)


[warning] 103-103: [UnorderedKey] The GITEA_INTERNAL_TOKEN key should go before the GITEA_SECRET_KEY key

(UnorderedKey)


[warning] 107-107: [QuoteCharacter] The value has quote characters (', ")

(QuoteCharacter)

🪛 markdownlint-cli2 (0.18.1)
docs/PRPs/containers/mssql-server.md

4-4: Bare URL used

(MD034, no-bare-urls)


6-6: Bare URL used

(MD034, no-bare-urls)

⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
  • GitHub Check: build
  • GitHub Check: check
🔇 Additional comments (10)
config-example/docker/myhost/services.yaml (4)

2-2: LGTM! Schema reference added for validation.

The yaml-language-server schema reference enables IDE validation and autocomplete, improving configuration maintainability.


50-53: LGTM! New automation services added.

The mosquitto MQTT broker and esphome-device-builder services are properly configured following the established pattern.


95-96: LGTM! New services added across categories.

The mssql-server (storage), gitea (dev), and obsidian (tools) services are correctly configured with consistent structure.

Also applies to: 109-110, 133-134


163-165: LGTM! Clear deprecation notice.

The TODO comment properly documents the planned migration from readarr to Lazy Librarian, maintaining traceability for future changes.

scripts/labctl.py (6)

29-33: LGTM! Log options properly typed.

The DockerOptions dataclass correctly extends with log-related fields. The since: str | None = None type annotation is correct for Python 3.10+.


38-38: LGTM! Logs action added to allowed states.

The 'logs' operation is now properly recognized as a valid service action.


206-224: LGTM! Log flag builder is clean and correct.

The function properly translates DockerOptions into Docker Compose log command flags, correctly handling the "all" default for tail and conditional flag inclusion.


283-288: LGTM! Logs case properly implemented.

The logs action correctly constructs the Docker Compose logs command with environment files, flags, and the service name. The service name appended at line 287 corresponds to the service defined within the compose file, following the codebase convention of one service per compose file.


385-401: LGTM! Conditional log options handling.

The implementation correctly populates log options only when the operation is 'logs', using hasattr for safe attribute checking.


426-430: LGTM! Standard Docker log options exposed.

The CLI arguments match standard Docker Compose logs options with appropriate short forms and defaults.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@coderabbitai coderabbitai 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.

Actionable comments posted: 3

🧹 Nitpick comments (4)
config-example/docker/myhost/services.yaml (1)

49-51: Fix Mosquitto entry formatting.

There’s a trailing blank line with spaces after the Mosquitto block. Trim it to keep YAML clean and satisfy linters.

docs/PRPs/containers/obsidian.md (1)

4-6: Wrap bare URLs to satisfy markdownlint.

markdownlint (MD034) flags bare URLs—wrap them in angle brackets or convert to Markdown links to keep the doc lint-clean.

config-example/docker/myhost/.env (1)

12-12: Maintain storage key ordering.

dotenv-linter flags key order; move STORAGE_OBSIDIAN up next to the other STORAGE_LOCAL_MEDIA/* entries (before STORAGE_WEBDAV) to keep the file passing lint.

docs/PRPs/containers/mosquitto.md (1)

4-6: Fix markdownlint MD034 violations.

Wrap the bare URLs in angle brackets or convert them to Markdown links so the doc passes markdownlint.

📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between e9df62f and 5367e1a.

📒 Files selected for processing (8)
  • config-example/docker/myhost/.env (2 hunks)
  • config-example/docker/myhost/services.yaml (2 hunks)
  • docker/Taskfile.apps.yaml (2 hunks)
  • docker/automation/mosquitto.yaml (1 hunks)
  • docker/automation/mosquitto/mosquitto.conf (1 hunks)
  • docker/tools/obsidian.yaml (1 hunks)
  • docs/PRPs/containers/mosquitto.md (1 hunks)
  • docs/PRPs/containers/obsidian.md (1 hunks)
🧰 Additional context used
📓 Path-based instructions (2)
**/*.{yml,yaml}

📄 CodeRabbit inference engine (AGENTS.md)

All YAML files must be linted and validated via pre-commit

Files:

  • config-example/docker/myhost/services.yaml
  • docker/automation/mosquitto.yaml
  • docker/tools/obsidian.yaml
  • docker/Taskfile.apps.yaml
docker/{security,media,storage,monitoring,ai,tools}/**/*.{yml,yaml}

📄 CodeRabbit inference engine (AGENTS.md)

docker/{security,media,storage,monitoring,ai,tools}/**/*.{yml,yaml}: Place Docker service definitions as YAML files under the appropriate category directory in docker/ (security, media, storage, monitoring, ai, tools)
When adding or modifying a service, create or edit its YAML definition in the appropriate docker// directory

Files:

  • docker/tools/obsidian.yaml
🧬 Code graph analysis (1)
docker/tools/obsidian.yaml (1)
docs/web/update-docs.py (1)
  • process_docker_compose_file (296-338)
🪛 dotenv-linter (3.3.0)
config-example/docker/myhost/.env

[warning] 12-12: [UnorderedKey] The STORAGE_OBSIDIAN key should go before the STORAGE_WEBDAV key

(UnorderedKey)

🪛 markdownlint-cli2 (0.18.1)
docs/PRPs/containers/obsidian.md

4-4: Bare URL used

(MD034, no-bare-urls)


5-5: Bare URL used

(MD034, no-bare-urls)


6-6: Bare URL used

(MD034, no-bare-urls)

docs/PRPs/containers/mosquitto.md

4-4: Bare URL used

(MD034, no-bare-urls)


5-5: Bare URL used

(MD034, no-bare-urls)


6-6: Bare URL used

(MD034, no-bare-urls)

⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
  • GitHub Check: build
  • GitHub Check: check

Comment thread config-example/docker/myhost/services.yaml Outdated
Comment thread docker/automation/mosquitto/mosquitto.conf
Comment thread docker/Taskfile.apps.yaml Outdated
@bubacoder
bubacoder force-pushed the feature/new-services branch from 5367e1a to 2a2ee4d Compare October 5, 2025 20:15

@coderabbitai coderabbitai 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.

Actionable comments posted: 4

🧹 Nitpick comments (1)
docker/tools/obsidian.yaml (1)

15-15: Pin the Obsidian image to a fixed tag or digest.

Pulling latest on every deploy risks silently replacing a working build with an untested upstream change. Please lock the image to a specific release tag or digest that you’ve validated in your environment to keep deployments reproducible.

📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 5367e1a and 2a2ee4d.

📒 Files selected for processing (14)
  • AGENTS.md (1 hunks)
  • README.md (1 hunks)
  • Taskfile.yaml (1 hunks)
  • config-example/docker/myhost/.env (2 hunks)
  • config-example/docker/myhost/services.yaml (4 hunks)
  • config-example/docker/services-schema.yaml (1 hunks)
  • docker/Taskfile.apps.yaml (2 hunks)
  • docker/Taskfile.docker.yaml (1 hunks)
  • docker/automation/mosquitto.yaml (1 hunks)
  • docker/automation/mosquitto/mosquitto.conf (1 hunks)
  • docker/tools/obsidian.yaml (1 hunks)
  • docs/PRPs/containers/mosquitto.md (1 hunks)
  • docs/PRPs/containers/obsidian.md (1 hunks)
  • scripts/update-example-env.py (1 hunks)
✅ Files skipped from review due to trivial changes (2)
  • scripts/update-example-env.py
  • README.md
🚧 Files skipped from review as they are similar to previous changes (3)
  • docker/automation/mosquitto/mosquitto.conf
  • config-example/docker/myhost/services.yaml
  • docker/Taskfile.apps.yaml
🧰 Additional context used
📓 Path-based instructions (2)
**/*.{yml,yaml}

📄 CodeRabbit inference engine (AGENTS.md)

All YAML files must be linted and validated via pre-commit

Files:

  • config-example/docker/services-schema.yaml
  • docker/Taskfile.docker.yaml
  • docker/automation/mosquitto.yaml
  • Taskfile.yaml
  • docker/tools/obsidian.yaml
docker/{security,media,storage,monitoring,ai,tools}/**/*.{yml,yaml}

📄 CodeRabbit inference engine (AGENTS.md)

docker/{security,media,storage,monitoring,ai,tools}/**/*.{yml,yaml}: Place Docker service definitions as YAML files under the appropriate category directory in docker/ (security, media, storage, monitoring, ai, tools)
When adding or modifying a service, create or edit its YAML definition in the appropriate docker// directory

Files:

  • docker/tools/obsidian.yaml
🧠 Learnings (2)
📚 Learning: 2025-09-28T17:29:15.156Z
Learnt from: CR
PR: bubacoder/infra#0
File: AGENTS.md:0-0
Timestamp: 2025-09-28T17:29:15.156Z
Learning: Applies to docker/{security,media,storage,monitoring,ai,tools}/**/*.{yml,yaml} : Place Docker service definitions as YAML files under the appropriate category directory in docker/ (security, media, storage, monitoring, ai, tools)

Applied to files:

  • config-example/docker/services-schema.yaml
📚 Learning: 2025-09-28T17:29:15.156Z
Learnt from: CR
PR: bubacoder/infra#0
File: AGENTS.md:0-0
Timestamp: 2025-09-28T17:29:15.156Z
Learning: Applies to docker/{security,media,storage,monitoring,ai,tools}/**/*.{yml,yaml} : When adding or modifying a service, create or edit its YAML definition in the appropriate docker/<category>/ directory

Applied to files:

  • config-example/docker/services-schema.yaml
🪛 dotenv-linter (3.3.0)
config-example/docker/myhost/.env

[warning] 12-12: [UnorderedKey] The STORAGE_OBSIDIAN key should go before the STORAGE_WEBDAV key

(UnorderedKey)

🪛 markdownlint-cli2 (0.18.1)
docs/PRPs/containers/mosquitto.md

4-4: Bare URL used

(MD034, no-bare-urls)


5-5: Bare URL used

(MD034, no-bare-urls)


6-6: Bare URL used

(MD034, no-bare-urls)


9-9: Bare URL used

(MD034, no-bare-urls)


80-80: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


90-90: Fenced code blocks should have a language specified

(MD040, fenced-code-language)

docs/PRPs/containers/obsidian.md

4-4: Bare URL used

(MD034, no-bare-urls)


5-5: Bare URL used

(MD034, no-bare-urls)


6-6: Bare URL used

(MD034, no-bare-urls)


9-9: Bare URL used

(MD034, no-bare-urls)

⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
  • GitHub Check: build
  • GitHub Check: check

Comment thread config-example/docker/myhost/.env
Comment thread docs/PRPs/containers/mosquitto.md
Comment thread docs/PRPs/containers/mosquitto.md
Comment thread docs/PRPs/containers/obsidian.md
@bubacoder
bubacoder force-pushed the feature/new-services branch from 2a2ee4d to d1502d7 Compare October 6, 2025 06:48

@coderabbitai coderabbitai 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.

Actionable comments posted: 0

♻️ Duplicate comments (2)
docs/PRPs/containers/mosquitto.md (2)

4-9: Wrap the bare URLs in Markdown links.

MD034 from markdownlint still fires here—please convert each bare URL to [label](url) so the lint job passes.

-Homepage: https://mosquitto.org/
-GitHub page: https://github.com/eclipse/mosquitto
-Install instructions URL: https://hub.docker.com/_/eclipse-mosquitto
-Container image(s): eclipse-mosquitto:2.0.22-openssl
-Category: automation
-Dashboard Icon: https://mosquitto.org/favicon-16x16.png
+Homepage: [mosquitto.org](https://mosquitto.org/)
+GitHub page: [github.com/eclipse/mosquitto](https://github.com/eclipse/mosquitto)
+Install instructions URL: [hub.docker.com/_/eclipse-mosquitto](https://hub.docker.com/_/eclipse-mosquitto)
+Container image(s): `eclipse-mosquitto:2.0.22-openssl`
+Category: automation
+Dashboard Icon: [mosquitto.org favicon](https://mosquitto.org/favicon-16x16.png)

Based on static analysis hints.


80-114: Add language identifiers to these code fences.

MD040 is still complaining about the directory tree and config sample fences—tag them with a language (text, conf, etc.) so linting succeeds.

-   ```
+   ```text
@@
-   ```
+   ```conf

Based on static analysis hints.

🧹 Nitpick comments (1)
config-example/docker/services-schema.yaml (1)

8-51: Require services and tighten service object schema.

Without a required clause the schema accepts an empty root object, and service objects can carry arbitrary keys. Tightening those constraints helps the validation actually catch malformed configs.

 properties:
   services:
     type: array
     description: Categories of Docker services
+    minItems: 1
     items:
       type: object
       additionalProperties:
         type: array
         description: List of services in a specific category
         items:
           type: object
           required:
             - name
             - state
           properties:
             name:
               type: string
               description: Name of the Docker service
             state:
               type: string
               description: Current state of the service
               enum:
                 - up
                 - down
             note:
               type: string
               description: Optional note about the service
+          additionalProperties: false
+required:
+  - services
 additionalProperties: false
📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 2a2ee4d and d1502d7.

📒 Files selected for processing (10)
  • AGENTS.md (1 hunks)
  • README.md (1 hunks)
  • Taskfile.yaml (1 hunks)
  • config-example/docker/myhost/services.yaml (4 hunks)
  • config-example/docker/services-schema.yaml (1 hunks)
  • docker/Taskfile.docker.yaml (1 hunks)
  • docker/automation/mosquitto.yaml (1 hunks)
  • docker/automation/mosquitto/mosquitto.conf (1 hunks)
  • docs/PRPs/containers/mosquitto.md (1 hunks)
  • scripts/update-example-env.py (1 hunks)
✅ Files skipped from review due to trivial changes (2)
  • README.md
  • scripts/update-example-env.py
🚧 Files skipped from review as they are similar to previous changes (3)
  • docker/automation/mosquitto/mosquitto.conf
  • Taskfile.yaml
  • AGENTS.md
🧰 Additional context used
📓 Path-based instructions (1)
**/*.{yml,yaml}

📄 CodeRabbit inference engine (AGENTS.md)

All YAML files must be linted and validated via pre-commit

Files:

  • config-example/docker/myhost/services.yaml
  • docker/Taskfile.docker.yaml
  • docker/automation/mosquitto.yaml
  • config-example/docker/services-schema.yaml
🧠 Learnings (3)
📚 Learning: 2025-09-28T17:29:15.156Z
Learnt from: CR
PR: bubacoder/infra#0
File: AGENTS.md:0-0
Timestamp: 2025-09-28T17:29:15.156Z
Learning: Applies to config/docker/*/services.yaml : Add each service to the host-specific configuration at config/docker/<hostname>/services.yaml

Applied to files:

  • config-example/docker/myhost/services.yaml
📚 Learning: 2025-09-28T17:29:15.156Z
Learnt from: CR
PR: bubacoder/infra#0
File: AGENTS.md:0-0
Timestamp: 2025-09-28T17:29:15.156Z
Learning: Applies to docker/{security,media,storage,monitoring,ai,tools}/**/*.{yml,yaml} : Place Docker service definitions as YAML files under the appropriate category directory in docker/ (security, media, storage, monitoring, ai, tools)

Applied to files:

  • config-example/docker/services-schema.yaml
📚 Learning: 2025-09-28T17:29:15.156Z
Learnt from: CR
PR: bubacoder/infra#0
File: AGENTS.md:0-0
Timestamp: 2025-09-28T17:29:15.156Z
Learning: Applies to docker/{security,media,storage,monitoring,ai,tools}/**/*.{yml,yaml} : When adding or modifying a service, create or edit its YAML definition in the appropriate docker/<category>/ directory

Applied to files:

  • config-example/docker/services-schema.yaml
🪛 markdownlint-cli2 (0.18.1)
docs/PRPs/containers/mosquitto.md

4-4: Bare URL used

(MD034, no-bare-urls)


5-5: Bare URL used

(MD034, no-bare-urls)


6-6: Bare URL used

(MD034, no-bare-urls)


9-9: Bare URL used

(MD034, no-bare-urls)


80-80: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


90-90: Fenced code blocks should have a language specified

(MD040, fenced-code-language)

⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
  • GitHub Check: build
  • GitHub Check: check

@bubacoder
bubacoder force-pushed the feature/new-services branch from d1502d7 to bb34046 Compare October 6, 2025 13:11

@coderabbitai coderabbitai 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.

Actionable comments posted: 1

♻️ Duplicate comments (1)
config-example/docker/myhost/.env (1)

10-12: Keep keys sorted for dotenv-linter

Please move STORAGE_OBSIDIAN before STORAGE_WEBDAV so the storage block stays alphabetically sorted and the pre-commit dotenv-linter check keeps passing.

Apply this diff:

-STORAGE_WEBDAV=${STORAGE_LOCAL_MEDIA}/webdav
-STORAGE_KIWIX=${STORAGE_LOCAL_MEDIA}/kiwix
-STORAGE_OBSIDIAN=${STORAGE_LOCAL_MEDIA}/obsidian
+STORAGE_OBSIDIAN=${STORAGE_LOCAL_MEDIA}/obsidian
+STORAGE_WEBDAV=${STORAGE_LOCAL_MEDIA}/webdav
+STORAGE_KIWIX=${STORAGE_LOCAL_MEDIA}/kiwix
📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between d1502d7 and bb34046.

📒 Files selected for processing (14)
  • AGENTS.md (1 hunks)
  • README.md (1 hunks)
  • Taskfile.yaml (3 hunks)
  • config-example/docker/myhost/.env (2 hunks)
  • config-example/docker/myhost/services.yaml (4 hunks)
  • config-example/docker/services-schema.yaml (1 hunks)
  • docker/Taskfile.docker.yaml (1 hunks)
  • docker/automation/mosquitto.yaml (1 hunks)
  • docker/automation/mosquitto/mosquitto.conf (1 hunks)
  • docker/tools/Taskfile.obsidian.yaml (1 hunks)
  • docker/tools/obsidian.yaml (1 hunks)
  • docs/PRPs/containers/mosquitto.md (1 hunks)
  • docs/PRPs/containers/obsidian.md (1 hunks)
  • scripts/update-example-env.py (1 hunks)
✅ Files skipped from review due to trivial changes (2)
  • docker/automation/mosquitto/mosquitto.conf
  • AGENTS.md
🚧 Files skipped from review as they are similar to previous changes (8)
  • scripts/update-example-env.py
  • docs/PRPs/containers/obsidian.md
  • config-example/docker/myhost/services.yaml
  • docs/PRPs/containers/mosquitto.md
  • README.md
  • config-example/docker/services-schema.yaml
  • docker/automation/mosquitto.yaml
  • docker/Taskfile.docker.yaml
🧰 Additional context used
📓 Path-based instructions (2)
**/*.{yml,yaml}

📄 CodeRabbit inference engine (AGENTS.md)

All YAML files must be linted and validated via pre-commit

Files:

  • docker/tools/obsidian.yaml
  • docker/tools/Taskfile.obsidian.yaml
  • Taskfile.yaml
docker/{security,media,storage,monitoring,ai,tools}/**/*.{yml,yaml}

📄 CodeRabbit inference engine (AGENTS.md)

docker/{security,media,storage,monitoring,ai,tools}/**/*.{yml,yaml}: Place Docker service definitions as YAML files under the appropriate category directory in docker/ (security, media, storage, monitoring, ai, tools)
When adding or modifying a service, create or edit its YAML definition in the appropriate docker// directory

Files:

  • docker/tools/obsidian.yaml
  • docker/tools/Taskfile.obsidian.yaml
🧬 Code graph analysis (1)
docker/tools/obsidian.yaml (1)
docs/web/update-docs.py (1)
  • process_docker_compose_file (296-338)
🪛 dotenv-linter (3.3.0)
config-example/docker/myhost/.env

[warning] 12-12: [UnorderedKey] The STORAGE_OBSIDIAN key should go before the STORAGE_WEBDAV key

(UnorderedKey)

⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
  • GitHub Check: check
  • GitHub Check: build

Comment thread docker/tools/Taskfile.obsidian.yaml
@bubacoder
bubacoder force-pushed the feature/new-services branch from bb34046 to 14e8bcb Compare October 12, 2025 10:50

@coderabbitai coderabbitai 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.

Actionable comments posted: 6

♻️ Duplicate comments (5)
config-example/docker/myhost/.env (1)

12-12: Reorder STORAGE_OBSIDIAN for dotenv-linter.

This issue was already flagged in a previous review. Please move STORAGE_OBSIDIAN ahead of STORAGE_WEBDAV to maintain alphabetical order and satisfy the linter.

Based on static analysis hints

docs/PRPs/containers/obsidian.md (1)

4-7: Wrap base URLs in Markdown links.

The bare links still violate MD034; please convert the metadata lines to [label](url) form so markdownlint passes.
Apply this diff:

-Homepage: https://obsidian.md
-GitHub page: https://github.com/obsidianmd
-Install instructions URL: https://docs.linuxserver.io/images/docker-obsidian/
-Container image(s): lscr.io/linuxserver/obsidian:latest
+Homepage: [obsidian.md](https://obsidian.md)
+GitHub page: [github.com/obsidianmd](https://github.com/obsidianmd)
+Install instructions URL: [docs.linuxserver.io/images/docker-obsidian](https://docs.linuxserver.io/images/docker-obsidian/)
+Container image(s): [lscr.io/linuxserver/obsidian:latest](https://lscr.io/linuxserver/obsidian:latest)

Based on static analysis hints.

docs/PRPs/containers/mosquitto.md (2)

4-10: Convert metadata URLs to Markdown links.

These plain URLs still trigger MD034; wrap them in [text](url) syntax so linting succeeds.
Suggested patch:

-Homepage: https://mosquitto.org/
-GitHub page: https://github.com/eclipse/mosquitto
-Install instructions URL: https://hub.docker.com/_/eclipse-mosquitto
-Container image(s): eclipse-mosquitto:2.0.22-openssl
-Dashboard Icon: https://mosquitto.org/favicon-16x16.png
+Homepage: [mosquitto.org](https://mosquitto.org/)
+GitHub page: [github.com/eclipse/mosquitto](https://github.com/eclipse/mosquitto)
+Install instructions URL: [hub.docker.com/_/eclipse-mosquitto](https://hub.docker.com/_/eclipse-mosquitto)
+Container image(s): `eclipse-mosquitto:2.0.22-openssl`
+Dashboard Icon: [mosquitto.org/favicon-16x16.png](https://mosquitto.org/favicon-16x16.png)

Based on static analysis hints.


80-114: Tag fenced blocks with a language.

The directory tree and mosquitto.conf examples still lack language identifiers, tripping MD040. Add text/conf to the fences.
Proposed changes:

-   ```
+   ```text
@@
-   ```
+   ```conf

Based on static analysis hints.

docker/tools/Taskfile.obsidian.yaml (1)

13-41: Quote/slug vault variables to survive spaces.

OBSIDIAN_VAULT_NAME still flows through unquoted echo, realpath, cd, and rsync, so vaults like “Second Brain” break the workflow. Slug the repo name and quote every path expansion.
Apply:

-        REPO_NAME="$(echo -n ${OBSIDIAN_VAULT_NAME} | tr '[:upper:]' '[:lower:]')"
-        REPO_PATH="$(realpath -s ../${REPO_NAME})"
+        REPO_NAME="$(printf '%s' "${OBSIDIAN_VAULT_NAME}" | tr '[:upper:]' '[:lower:]' | tr ' ' '-')"
+        REPO_PATH="$(realpath -s "../${REPO_NAME}")"
@@
-        cd ${REPO_PATH} || { echo "Failed to cd to ${REPO_PATH}"; exit 1; }
+        cd "${REPO_PATH}" || { echo "Failed to cd to ${REPO_PATH}"; exit 1; }
@@
-        rsync --verbose --archive --delete --exclude ".obsidian/" --exclude ".git/" ${VAULT_PATH} .
+        rsync --verbose --archive --delete --exclude ".obsidian/" --exclude ".git/" "${VAULT_PATH}" .
@@
-        REPO_NAME="$(echo -n ${OBSIDIAN_VAULT_NAME} | tr '[:upper:]' '[:lower:]')"
-        REPO_PATH="$(realpath -s ../${REPO_NAME})"
-        cd ${REPO_PATH} || { echo "Failed to cd to ${REPO_PATH}"; exit 1; }
+        REPO_NAME="$(printf '%s' "${OBSIDIAN_VAULT_NAME}" | tr '[:upper:]' '[:lower:]' | tr ' ' '-')"
+        REPO_PATH="$(realpath -s "../${REPO_NAME}")"
+        cd "${REPO_PATH}" || { echo "Failed to cd to ${REPO_PATH}"; exit 1; }

Based on static analysis hints.

🧹 Nitpick comments (1)
scripts/labctl.py (1)

29-33: Consider modern type hint syntax for the since parameter.

The log options are well-structured. For Python 3.10+, consider using the union operator for the optional type hint.

Apply this diff:

     # Log options
     follow: bool = False
     tail: str = "all"
-    since: str = None
+    since: str | None = None
     timestamps: bool = False
📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between bb34046 and 14e8bcb.

📒 Files selected for processing (24)
  • .claude/commands/implement-container-deployment.md (1 hunks)
  • .pre-commit-config.yaml (1 hunks)
  • AGENTS.md (1 hunks)
  • README.md (1 hunks)
  • Taskfile.yaml (3 hunks)
  • config-example/docker/myhost/.env (2 hunks)
  • config-example/docker/myhost/services.yaml (6 hunks)
  • config-example/docker/services-schema.yaml (1 hunks)
  • docker/Taskfile.docker.yaml (1 hunks)
  • docker/automation/esphome-device-builder.yaml (1 hunks)
  • docker/automation/mosquitto.yaml (1 hunks)
  • docker/automation/mosquitto/mosquitto.conf (1 hunks)
  • docker/dev/gitea.yaml (1 hunks)
  • docker/guidelines.md (2 hunks)
  • docker/storage/mssql-server.yaml (1 hunks)
  • docker/tools/Taskfile.obsidian.yaml (1 hunks)
  • docker/tools/obsidian.yaml (1 hunks)
  • docs/PRPs/containers/esphome-device-builder.md (1 hunks)
  • docs/PRPs/containers/gitea.md (1 hunks)
  • docs/PRPs/containers/mosquitto.md (1 hunks)
  • docs/PRPs/containers/mssql-server.md (1 hunks)
  • docs/PRPs/containers/obsidian.md (1 hunks)
  • scripts/labctl.py (5 hunks)
  • scripts/update-example-env.py (1 hunks)
✅ Files skipped from review due to trivial changes (1)
  • README.md
🚧 Files skipped from review as they are similar to previous changes (6)
  • docker/automation/mosquitto/mosquitto.conf
  • Taskfile.yaml
  • config-example/docker/services-schema.yaml
  • scripts/update-example-env.py
  • docker/tools/obsidian.yaml
  • AGENTS.md
🧰 Additional context used
📓 Path-based instructions (3)
**/*.{yml,yaml}

📄 CodeRabbit inference engine (AGENTS.md)

All YAML files must be linted and validated via pre-commit

Files:

  • docker/storage/mssql-server.yaml
  • docker/automation/esphome-device-builder.yaml
  • docker/automation/mosquitto.yaml
  • docker/dev/gitea.yaml
  • config-example/docker/myhost/services.yaml
  • docker/Taskfile.docker.yaml
  • docker/tools/Taskfile.obsidian.yaml
docker/{security,media,storage,monitoring,ai,tools}/**/*.{yml,yaml}

📄 CodeRabbit inference engine (AGENTS.md)

docker/{security,media,storage,monitoring,ai,tools}/**/*.{yml,yaml}: Place Docker service definitions as YAML files under the appropriate category directory in docker/ (security, media, storage, monitoring, ai, tools)
When adding or modifying a service, create or edit its YAML definition in the appropriate docker// directory

Files:

  • docker/storage/mssql-server.yaml
  • docker/tools/Taskfile.obsidian.yaml
**/*.py

📄 CodeRabbit inference engine (AGENTS.md)

Python code must pass Ruff linting via pre-commit

Files:

  • scripts/labctl.py
🧠 Learnings (1)
📚 Learning: 2025-09-28T17:29:15.156Z
Learnt from: CR
PR: bubacoder/infra#0
File: AGENTS.md:0-0
Timestamp: 2025-09-28T17:29:15.156Z
Learning: Applies to config/docker/*/services.yaml : Add each service to the host-specific configuration at config/docker/<hostname>/services.yaml

Applied to files:

  • config-example/docker/myhost/services.yaml
🪛 dotenv-linter (3.3.0)
config-example/docker/myhost/.env

[warning] 12-12: [UnorderedKey] The STORAGE_OBSIDIAN key should go before the STORAGE_WEBDAV key

(UnorderedKey)

🪛 markdownlint-cli2 (0.18.1)
docs/PRPs/containers/gitea.md

4-4: Bare URL used

(MD034, no-bare-urls)


5-5: Bare URL used

(MD034, no-bare-urls)


6-6: Bare URL used

(MD034, no-bare-urls)


9-9: Bare URL used

(MD034, no-bare-urls)


80-80: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


90-90: Fenced code blocks should have a language specified

(MD040, fenced-code-language)

docs/PRPs/containers/mssql-server.md

4-4: Bare URL used

(MD034, no-bare-urls)


6-6: Bare URL used

(MD034, no-bare-urls)

docs/PRPs/containers/esphome-device-builder.md

4-4: Bare URL used

(MD034, no-bare-urls)


5-5: Bare URL used

(MD034, no-bare-urls)


6-6: Bare URL used

(MD034, no-bare-urls)

docs/PRPs/containers/mosquitto.md

4-4: Bare URL used

(MD034, no-bare-urls)


5-5: Bare URL used

(MD034, no-bare-urls)


6-6: Bare URL used

(MD034, no-bare-urls)


9-9: Bare URL used

(MD034, no-bare-urls)


80-80: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


90-90: Fenced code blocks should have a language specified

(MD040, fenced-code-language)

docs/PRPs/containers/obsidian.md

4-4: Bare URL used

(MD034, no-bare-urls)


5-5: Bare URL used

(MD034, no-bare-urls)


6-6: Bare URL used

(MD034, no-bare-urls)

⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
  • GitHub Check: build
  • GitHub Check: check
🔇 Additional comments (9)
.pre-commit-config.yaml (1)

13-17: LGTM! The multi-line regex pattern is well-structured.

The verbose regex pattern correctly excludes both directories, uses proper anchoring, and aligns with the new mosquitto automation content introduced in this PR.

docker/guidelines.md (2)

190-190: Good guidance for database deployments.

This addition correctly advises using named volumes for data-heavy applications like databases, which is a Docker best practice for better performance and management.


231-231: Helpful TODO template addition.

Adding a TODO placeholder in the template encourages developers to document additional configuration tasks and enhancements, improving service documentation quality.

docker/Taskfile.docker.yaml (1)

69-85: LGTM! Task rename and schema propagation are correct.

The rename from create-example-env to update-example-env better reflects the task's purpose. The addition of services-schema.yaml to both sources and generates correctly tracks the schema file propagation.

docker/dev/gitea.yaml (1)

11-52: Service configuration follows guidelines correctly.

The Gitea service is well-structured and follows the docker guidelines template with proper:

  • Version pinning (1.24.6)
  • Environment variable configuration
  • Volume management
  • Traefik integration
  • Homepage dashboard labels
  • SSH port mapping (222 to avoid host conflicts)
scripts/labctl.py (3)

206-224: LGTM! The log command builder is well-implemented.

The function correctly translates DockerOptions into docker compose logs flags, handling all the log-specific options appropriately.


283-288: LGTM! The logs action is properly integrated.

The logs case correctly constructs and executes the docker compose logs command with the appropriate flags and service name.


426-430: LGTM! CLI arguments for logs are well-defined.

The log-specific command-line arguments are properly configured with appropriate defaults and help text.

config-example/docker/myhost/.env (1)

94-97: Good addition of optional Obsidian authentication placeholders.

The commented authentication variables provide clear guidance for users who want to enable authentication for the Obsidian container.

Comment thread .claude/commands/implement-container-deployment.md Outdated
Comment thread docker/automation/esphome-device-builder.yaml
Comment thread docker/dev/gitea.yaml
Comment thread docs/PRPs/containers/gitea.md
Comment thread docs/PRPs/containers/mssql-server.md
@bubacoder
bubacoder force-pushed the feature/new-services branch from 14e8bcb to fe668bc Compare October 12, 2025 19:28

@coderabbitai coderabbitai 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.

Actionable comments posted: 4

♻️ Duplicate comments (4)
config-example/docker/myhost/.env (1)

10-12: Reorder storage keys to pass dotenv-linter.

Move STORAGE_OBSIDIAN before STORAGE_WEBDAV (alphabetical).

-STORAGE_WEBDAV=${STORAGE_LOCAL_MEDIA}/webdav
-STORAGE_KIWIX=${STORAGE_LOCAL_MEDIA}/kiwix
-STORAGE_OBSIDIAN=${STORAGE_LOCAL_MEDIA}/obsidian
+STORAGE_OBSIDIAN=${STORAGE_LOCAL_MEDIA}/obsidian
+STORAGE_WEBDAV=${STORAGE_LOCAL_MEDIA}/webdav
+STORAGE_KIWIX=${STORAGE_LOCAL_MEDIA}/kiwix
docs/PRPs/containers/mssql-server.md (1)

4-6: Wrap bare URLs to satisfy MD034.

-Homepage: https://www.microsoft.com/en-us/sql-server
-Install instructions URL: https://raw.githubusercontent.com/MicrosoftDocs/sql-docs/refs/heads/live/docs/linux/quickstart-install-connect-docker.md
+Homepage: [microsoft.com/en-us/sql-server](https://www.microsoft.com/en-us/sql-server)
+Install instructions URL: [quickstart-install-connect-docker.md](https://raw.githubusercontent.com/MicrosoftDocs/sql-docs/refs/heads/live/docs/linux/quickstart-install-connect-docker.md)
docs/PRPs/containers/esphome-device-builder.md (1)

4-7: Format base URLs as Markdown links (MD034).

-Homepage: https://esphome.io
-GitHub page: https://github.com/esphome/esphome
-Install instructions URL: https://esphome.io/guides/getting_started_command_line/#bonus-esphome-device-builder
-Container image(s): esphome/esphome:2025.11.0-dev20251010
+Homepage: [esphome.io](https://esphome.io)
+GitHub page: [github.com/esphome/esphome](https://github.com/esphome/esphome)
+Install instructions URL: [esphome.io/guides/getting_started_command_line/#bonus-esphome-device-builder](https://esphome.io/guides/getting_started_command_line/#bonus-esphome-device-builder)
+Container image(s): [esphome/esphome:2025.11.0-dev20251010](https://hub.docker.com/r/esphome/esphome/tags)
docker/automation/esphome-device-builder.yaml (1)

18-18: Traefik labels won’t work with host networking. Choose one fix.

Option A – Use bridge networking with Traefik (keeps labels; enables routing):

-    network_mode: host
+    # Attach to Traefik's network instead of host mode
+    networks:
+      - proxy
@@
-    # Not needed due to 'network_mode: host'
-    # ports:
-    #   - "6052:6052"
+    # No host ports needed when Traefik is on the same Docker network

Add networks block at file end:

+networks:
+  proxy:
+    external: true

Option B – Keep host networking; remove Traefik Docker labels (route via file/static provider instead):

-    network_mode: host
@@
-    labels:
-      traefik.enable: true
-      traefik.http.routers.esphome-device-builder.rule: Host(`esphome.${MYDOMAIN}`)
-      traefik.http.routers.esphome-device-builder.middlewares: localaccess@file
-      traefik.http.services.esphome-device-builder.loadbalancer.server.port: 6052
-      homepage.group: Automation
-      homepage.name: ESPHome Builder
-      homepage.icon: esphome.png
-      homepage.href: https://esphome.${MYDOMAIN}/
-      homepage.description: "Firmware builder for ESP devices"
+    # labels:
+    #   homepage.group: Automation
+    #   homepage.name: ESPHome Builder
+    #   homepage.icon: esphome.png
+    #   homepage.href: https://esphome.${MYDOMAIN}/
+    #   homepage.description: "Firmware builder for ESP devices"

Also applies to: 36-39

🧹 Nitpick comments (2)
scripts/labctl.py (2)

393-400: Consider simplifying log option assignment.

The hasattr checks are redundant since argparse always populates these attributes when the parser is defined (lines 427-430). The if args.operation == 'logs' guard on line 392 is sufficient.

You could simplify to:

     # Add log options if they exist in args and operation is 'logs'
     if args.operation == 'logs':
-        if hasattr(args, 'follow'):
-            options.follow = args.follow
-        if hasattr(args, 'tail'):
-            options.tail = args.tail
-        if hasattr(args, 'since'):
-            options.since = args.since
-        if hasattr(args, 'timestamps'):
-            options.timestamps = args.timestamps
+        options.follow = args.follow
+        options.tail = args.tail
+        options.since = args.since
+        options.timestamps = args.timestamps

426-430: Consider validating --tail and --since arguments.

The --tail argument accepts any string, but Docker Compose expects either "all" or a positive integer. Similarly, --since expects specific formats (e.g., "10m", "1h", RFC3339 timestamps). Without validation, users will receive cryptic Docker Compose error messages for invalid inputs.

You could add validation using argparse type parameter or a custom validation function. For example:

def validate_tail(value):
    if value == "all":
        return value
    try:
        int_value = int(value)
        if int_value < 0:
            raise argparse.ArgumentTypeError(f"tail must be 'all' or a non-negative integer")
        return value
    except ValueError:
        raise argparse.ArgumentTypeError(f"tail must be 'all' or a non-negative integer")

service_parser.add_argument('--tail', '-n', type=validate_tail, default="all", 
                           help='Number of lines to show from the end of logs (default: all)')

This would improve user experience by catching errors earlier with clearer messages.

📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 14e8bcb and fe668bc.

📒 Files selected for processing (11)
  • .claude/commands/implement-container-deployment.md (1 hunks)
  • config-example/docker/myhost/.env (2 hunks)
  • config-example/docker/myhost/services.yaml (6 hunks)
  • docker/automation/esphome-device-builder.yaml (1 hunks)
  • docker/dev/gitea.yaml (1 hunks)
  • docker/guidelines.md (2 hunks)
  • docker/storage/mssql-server.yaml (1 hunks)
  • docs/PRPs/containers/esphome-device-builder.md (1 hunks)
  • docs/PRPs/containers/gitea.md (1 hunks)
  • docs/PRPs/containers/mssql-server.md (1 hunks)
  • scripts/labctl.py (5 hunks)
🚧 Files skipped from review as they are similar to previous changes (4)
  • docker/storage/mssql-server.yaml
  • docker/dev/gitea.yaml
  • .claude/commands/implement-container-deployment.md
  • docker/guidelines.md
🧰 Additional context used
📓 Path-based instructions (2)
**/*.py

📄 CodeRabbit inference engine (AGENTS.md)

Python code must pass Ruff linting via pre-commit

Files:

  • scripts/labctl.py
**/*.{yml,yaml}

📄 CodeRabbit inference engine (AGENTS.md)

All YAML files must be linted and validated via pre-commit

Files:

  • config-example/docker/myhost/services.yaml
  • docker/automation/esphome-device-builder.yaml
🧠 Learnings (1)
📚 Learning: 2025-09-28T17:29:15.156Z
Learnt from: CR
PR: bubacoder/infra#0
File: AGENTS.md:0-0
Timestamp: 2025-09-28T17:29:15.156Z
Learning: Applies to config/docker/*/services.yaml : Add each service to the host-specific configuration at config/docker/<hostname>/services.yaml

Applied to files:

  • config-example/docker/myhost/services.yaml
🪛 dotenv-linter (3.3.0)
config-example/docker/myhost/.env

[warning] 12-12: [UnorderedKey] The STORAGE_OBSIDIAN key should go before the STORAGE_WEBDAV key

(UnorderedKey)


[warning] 101-101: [QuoteCharacter] The value has quote characters (', ")

(QuoteCharacter)


[warning] 103-103: [QuoteCharacter] The value has quote characters (', ")

(QuoteCharacter)


[warning] 103-103: [UnorderedKey] The GITEA_INTERNAL_TOKEN key should go before the GITEA_SECRET_KEY key

(UnorderedKey)


[warning] 107-107: [QuoteCharacter] The value has quote characters (', ")

(QuoteCharacter)

🪛 markdownlint-cli2 (0.18.1)
docs/PRPs/containers/mssql-server.md

4-4: Bare URL used

(MD034, no-bare-urls)


6-6: Bare URL used

(MD034, no-bare-urls)

docs/PRPs/containers/gitea.md

4-4: Bare URL used

(MD034, no-bare-urls)


5-5: Bare URL used

(MD034, no-bare-urls)


6-6: Bare URL used

(MD034, no-bare-urls)

⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
  • GitHub Check: build
  • GitHub Check: check
🔇 Additional comments (3)
scripts/labctl.py (2)

206-224: LGTM! Well-structured log flag builder.

The function correctly constructs Docker Compose log command flags based on the provided options. The logic for handling "all" as a special value for tail (line 218) aligns with Docker Compose's default behavior.


283-288: LGTM! Logs action properly integrated.

The logs case correctly constructs the command using build_log_command_flags and appends the service name to target logs for the specific service being managed.

config-example/docker/myhost/services.yaml (1)

50-53: New service entries look good and align with repo structure.

Additions for mosquitto, esphome-device-builder, mssql-server, gitea, and obsidian are consistent with corresponding compose files and the schema header.

Based on learnings

Also applies to: 95-96, 109-110, 133-134, 163-165

Comment thread config-example/docker/myhost/.env
Comment thread config-example/docker/myhost/.env
Comment thread docs/PRPs/containers/gitea.md
Comment thread scripts/labctl.py

@coderabbitai coderabbitai 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.

Actionable comments posted: 4

♻️ Duplicate comments (3)
docker/automation/esphome-device-builder.yaml (1)

18-39: Host networking breaks the Traefik labels.

With network_mode: host, Traefik’s Docker provider can’t see this container, so the router/service labels never attach and https://esphome.${MYDOMAIN} won’t resolve. Either drop host networking and join the Traefik network (publishing 6052) or keep host mode but remove these labels and configure Traefik via another provider.

config-example/docker/myhost/.env (1)

10-12: Fix dotenv-linter ordering for storage paths.

Line 12 puts STORAGE_OBSIDIAN after STORAGE_WEBDAV, which still breaks the alphabetical ordering lint (UnorderedKey). Please move STORAGE_OBSIDIAN before STORAGE_WEBDAV.

docs/PRPs/containers/mssql-server.md (1)

3-7: Convert the metadata URLs to Markdown links.

MD034 (no-bare-urls) is still triggered for the Homepage and Install instructions entries. Please wrap them in [text](url) format.

Apply this diff:

-Homepage: https://www.microsoft.com/en-us/sql-server
-Install instructions URL: https://raw.githubusercontent.com/MicrosoftDocs/sql-docs/refs/heads/live/docs/linux/quickstart-install-connect-docker.md
+Homepage: [microsoft.com/en-us/sql-server](https://www.microsoft.com/en-us/sql-server)
+Install instructions URL: [quickstart-install-connect-docker.md](https://raw.githubusercontent.com/MicrosoftDocs/sql-docs/refs/heads/live/docs/linux/quickstart-install-connect-docker.md)
📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 14e8bcb and fe668bc.

📒 Files selected for processing (11)
  • .claude/commands/implement-container-deployment.md (1 hunks)
  • config-example/docker/myhost/.env (2 hunks)
  • config-example/docker/myhost/services.yaml (6 hunks)
  • docker/automation/esphome-device-builder.yaml (1 hunks)
  • docker/dev/gitea.yaml (1 hunks)
  • docker/guidelines.md (2 hunks)
  • docker/storage/mssql-server.yaml (1 hunks)
  • docs/PRPs/containers/esphome-device-builder.md (1 hunks)
  • docs/PRPs/containers/gitea.md (1 hunks)
  • docs/PRPs/containers/mssql-server.md (1 hunks)
  • scripts/labctl.py (5 hunks)
🚧 Files skipped from review as they are similar to previous changes (4)
  • docker/storage/mssql-server.yaml
  • config-example/docker/myhost/services.yaml
  • docker/dev/gitea.yaml
  • docker/guidelines.md
🧰 Additional context used
📓 Path-based instructions (2)
**/*.py

📄 CodeRabbit inference engine (AGENTS.md)

Python code must pass Ruff linting via pre-commit

Files:

  • scripts/labctl.py
**/*.{yml,yaml}

📄 CodeRabbit inference engine (AGENTS.md)

All YAML files must be linted and validated via pre-commit

Files:

  • docker/automation/esphome-device-builder.yaml
🪛 dotenv-linter (3.3.0)
config-example/docker/myhost/.env

[warning] 12-12: [UnorderedKey] The STORAGE_OBSIDIAN key should go before the STORAGE_WEBDAV key

(UnorderedKey)


[warning] 101-101: [QuoteCharacter] The value has quote characters (', ")

(QuoteCharacter)


[warning] 103-103: [QuoteCharacter] The value has quote characters (', ")

(QuoteCharacter)


[warning] 103-103: [UnorderedKey] The GITEA_INTERNAL_TOKEN key should go before the GITEA_SECRET_KEY key

(UnorderedKey)


[warning] 107-107: [QuoteCharacter] The value has quote characters (', ")

(QuoteCharacter)

🪛 markdownlint-cli2 (0.18.1)
docs/PRPs/containers/esphome-device-builder.md

4-4: Bare URL used

(MD034, no-bare-urls)


6-6: Bare URL used

(MD034, no-bare-urls)

docs/PRPs/containers/mssql-server.md

4-4: Bare URL used

(MD034, no-bare-urls)


6-6: Bare URL used

(MD034, no-bare-urls)

docs/PRPs/containers/gitea.md

4-4: Bare URL used

(MD034, no-bare-urls)


5-5: Bare URL used

(MD034, no-bare-urls)


6-6: Bare URL used

(MD034, no-bare-urls)

🔇 Additional comments (6)
.claude/commands/implement-container-deployment.md (1)

16-16: Clear abort condition wording looks good.

The updated instruction now clearly covers both missing and absent files, reducing ambiguity for the agent workflow.

scripts/labctl.py (5)

38-38: LGTM!

The addition of 'logs' to ALLOWED_STATES is correct and enables the new logs functionality.


206-224: LGTM!

The function correctly constructs Docker Compose logs flags based on the provided options. The logic properly handles default values and conditional flag inclusion.


283-288: LGTM!

The logs case correctly implements the Docker Compose logs command structure with proper flag ordering: base command → options → service name.


385-401: LGTM!

The logic correctly populates log options into DockerOptions only when the operation is 'logs'. The hasattr checks are defensive programming that doesn't hurt, and the approach of silently ignoring log options for non-log operations is reasonable.


426-430: LGTM!

The CLI arguments for logs functionality are well-defined with appropriate flags, defaults, and help text that align with Docker Compose conventions.

Comment thread config-example/docker/myhost/.env
Comment thread docs/PRPs/containers/esphome-device-builder.md
Comment thread docs/PRPs/containers/gitea.md
Comment thread scripts/labctl.py Outdated
@bubacoder
bubacoder force-pushed the feature/new-services branch from fe668bc to cbad2db Compare October 13, 2025 19:29
@bubacoder bubacoder changed the title Add Obsidian (with git sync) and Eclipse Mosquitto MQTT broker Add Obsidian (with git sync) and Eclipse Mosquitto MQTT broker, Gitea, ESPHome, MS SQL Server 2025 Oct 13, 2025
@bubacoder bubacoder changed the title Add Obsidian (with git sync) and Eclipse Mosquitto MQTT broker, Gitea, ESPHome, MS SQL Server 2025 Add Obsidian (with git sync), Eclipse Mosquitto, Gitea, ESPHome and MS SQL Server 2025 Oct 13, 2025

@coderabbitai coderabbitai 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.

Actionable comments posted: 3

♻️ Duplicate comments (8)
docs/PRPs/containers/esphome-device-builder.md (1)

4-7: Fix markdownlint MD034 by wrapping URLs in links.

Replace each bare URL with [label](url) formatting so markdownlint passes (e.g., Homepage: [esphome.io](https://esphome.io)).

docs/PRPs/containers/mosquitto.md (2)

4-9: Wrap bare URLs in Markdown links.

Bare URLs trigger markdownlint MD034. Please convert each line to [label](url) so the docs lint passes.

Apply this diff (adjust labels as needed):

-Homepage: https://mosquitto.org/
-GitHub page: https://github.com/eclipse/mosquitto
-Install instructions URL: https://hub.docker.com/_/eclipse-mosquitto
-Dashboard Icon: https://mosquitto.org/favicon-16x16.png
+Homepage: [mosquitto.org](https://mosquitto.org/)
+GitHub page: [github.com/eclipse/mosquitto](https://github.com/eclipse/mosquitto)
+Install instructions URL: [hub.docker.com/_/eclipse-mosquitto](https://hub.docker.com/_/eclipse-mosquitto)
+Dashboard Icon: [mosquitto.org/favicon-16x16.png](https://mosquitto.org/favicon-16x16.png)

81-114: Add language identifiers to the remaining code fences.

markdownlint MD040 still flags the directory listing and mosquitto.conf sample because the opening fences lack a language tag. Add text/conf so lint passes.

Suggested diff:

-   ```
+   ```text
    ./mosquitto/
    ├── config/
@@
-   ```
+   ```conf
    # Persistence settings
    persistence true
config-example/docker/myhost/.env (3)

10-12: Fix key ordering for dotenv-linter.

Alphabetize STORAGE_* entries: KIWIX < OBSIDIAN < WEBDAV.

-STORAGE_WEBDAV=${STORAGE_LOCAL_MEDIA}/webdav
-STORAGE_KIWIX=${STORAGE_LOCAL_MEDIA}/kiwix
-STORAGE_OBSIDIAN=${STORAGE_LOCAL_MEDIA}/obsidian
+STORAGE_KIWIX=${STORAGE_LOCAL_MEDIA}/kiwix
+STORAGE_OBSIDIAN=${STORAGE_LOCAL_MEDIA}/obsidian
+STORAGE_WEBDAV=${STORAGE_LOCAL_MEDIA}/webdav

99-104: Gitea: reorder keys and drop quotes (dotenv-linter).

Place INTERNAL_TOKEN before SECRET_KEY; remove quotes.

-### Gitea configuration
-# Generate these with: docker run --rm gitea/gitea:1.24.6 gitea generate secret SECRET_KEY
-GITEA_SECRET_KEY="use-some-very-secure-value-here"
-# Generate these with: docker run --rm gitea/gitea:1.24.6 gitea generate secret INTERNAL_TOKEN
-GITEA_INTERNAL_TOKEN="use-some-very-secure-value-here"
+### Gitea configuration
+# Generate this with: docker run --rm gitea/gitea:1.24.6 gitea generate secret INTERNAL_TOKEN
+GITEA_INTERNAL_TOKEN=use-some-very-secure-value-here
+# Generate this with: docker run --rm gitea/gitea:1.24.6 gitea generate secret SECRET_KEY
+GITEA_SECRET_KEY=use-some-very-secure-value-here

105-109: MSSQL: drop quotes from MSSQL_SA_PASSWORD (dotenv-linter).

Remove surrounding quotes.

-MSSQL_SA_PASSWORD="use-some-very-secure-value-here"
+MSSQL_SA_PASSWORD=use-some-very-secure-value-here
docs/PRPs/containers/mssql-server.md (1)

4-7: Wrap metadata URLs (MD034).

Use text links.

-Homepage: https://www.microsoft.com/en-us/sql-server
+Homepage: [microsoft.com/en-us/sql-server](https://www.microsoft.com/en-us/sql-server)
 GitHub page: N/A (proprietary software)
-Install instructions URL: https://raw.githubusercontent.com/MicrosoftDocs/sql-docs/refs/heads/live/docs/linux/quickstart-install-connect-docker.md
+Install instructions URL: [quickstart-install-connect-docker.md](https://raw.githubusercontent.com/MicrosoftDocs/sql-docs/refs/heads/live/docs/linux/quickstart-install-connect-docker.md)
docs/PRPs/containers/gitea.md (1)

4-6: Wrap bare URLs to satisfy markdownlint (MD034).

Convert to Markdown links.

-Homepage: https://about.gitea.com/
-GitHub page: https://github.com/go-gitea/gitea
-Install instructions URL: https://docs.gitea.com/installation/install-with-docker
+Homepage: [about.gitea.com](https://about.gitea.com/)
+GitHub page: [github.com/go-gitea/gitea](https://github.com/go-gitea/gitea)
+Install instructions URL: [docs.gitea.com/installation/install-with-docker](https://docs.gitea.com/installation/install-with-docker)
🧹 Nitpick comments (2)
scripts/labctl.py (2)

206-224: Function implementation is correct.

The build_log_command_flags function correctly constructs Docker Compose log command flags based on the provided options. The logic properly handles all log-related parameters.

Consider adding input validation for the tail and since parameters to provide earlier feedback on invalid values. For example:

  • tail should be either "all" or a positive integer
  • since should match Docker's expected timestamp format (e.g., "2h", "10m", RFC3339 timestamp)

However, since Docker Compose will validate these values anyway and provide appropriate error messages, this validation is optional and could be deferred.


385-402: Log options handling is implemented correctly.

The conditional population of log-related options when operation == 'logs' is correct and ensures that log parameters are only applied for the logs operation.

The hasattr checks on lines 393-400 are defensive but potentially unnecessary since these arguments are always defined by argparse (lines 427-430). You could simplify this to directly access the attributes:

-    # Add log options if they exist in args and operation is 'logs'
     if args.operation == 'logs':
-        if hasattr(args, 'follow'):
-            options.follow = args.follow
-        if hasattr(args, 'tail'):
-            options.tail = args.tail
-        if hasattr(args, 'since'):
-            options.since = args.since
-        if hasattr(args, 'timestamps'):
-            options.timestamps = args.timestamps
+        options.follow = args.follow
+        options.tail = args.tail
+        options.since = args.since
+        options.timestamps = args.timestamps

However, the defensive approach doesn't harm and may improve robustness if the function is called in other contexts.

📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between fe668bc and cbad2db.

📒 Files selected for processing (24)
  • .claude/commands/implement-container-deployment.md (1 hunks)
  • .pre-commit-config.yaml (1 hunks)
  • AGENTS.md (1 hunks)
  • README.md (1 hunks)
  • Taskfile.yaml (3 hunks)
  • config-example/docker/myhost/.env (2 hunks)
  • config-example/docker/myhost/services.yaml (6 hunks)
  • config-example/docker/services-schema.yaml (1 hunks)
  • docker/Taskfile.docker.yaml (1 hunks)
  • docker/automation/esphome-device-builder.yaml (1 hunks)
  • docker/automation/mosquitto.yaml (1 hunks)
  • docker/automation/mosquitto/mosquitto.conf (1 hunks)
  • docker/dev/gitea.yaml (1 hunks)
  • docker/guidelines.md (2 hunks)
  • docker/storage/mssql-server.yaml (1 hunks)
  • docker/tools/Taskfile.obsidian.yaml (1 hunks)
  • docker/tools/obsidian.yaml (1 hunks)
  • docs/PRPs/containers/esphome-device-builder.md (1 hunks)
  • docs/PRPs/containers/gitea.md (1 hunks)
  • docs/PRPs/containers/mosquitto.md (1 hunks)
  • docs/PRPs/containers/mssql-server.md (1 hunks)
  • docs/PRPs/containers/obsidian.md (1 hunks)
  • scripts/labctl.py (5 hunks)
  • scripts/update-example-env.py (1 hunks)
✅ Files skipped from review due to trivial changes (1)
  • docs/PRPs/containers/obsidian.md
🚧 Files skipped from review as they are similar to previous changes (15)
  • config-example/docker/services-schema.yaml
  • README.md
  • docker/automation/mosquitto.yaml
  • config-example/docker/myhost/services.yaml
  • docker/automation/mosquitto/mosquitto.conf
  • docker/tools/obsidian.yaml
  • AGENTS.md
  • docker/automation/esphome-device-builder.yaml
  • .pre-commit-config.yaml
  • scripts/update-example-env.py
  • Taskfile.yaml
  • docker/Taskfile.docker.yaml
  • docker/storage/mssql-server.yaml
  • docker/dev/gitea.yaml
  • .claude/commands/implement-container-deployment.md
🧰 Additional context used
📓 Path-based instructions (3)
**/*.{yml,yaml}

📄 CodeRabbit inference engine (AGENTS.md)

All YAML files must be linted and validated via pre-commit

Files:

  • docker/tools/Taskfile.obsidian.yaml
docker/{security,media,storage,monitoring,ai,tools}/**/*.{yml,yaml}

📄 CodeRabbit inference engine (AGENTS.md)

docker/{security,media,storage,monitoring,ai,tools}/**/*.{yml,yaml}: Place Docker service definitions as YAML files under the appropriate category directory in docker/ (security, media, storage, monitoring, ai, tools)
When adding or modifying a service, create or edit its YAML definition in the appropriate docker// directory

Files:

  • docker/tools/Taskfile.obsidian.yaml
**/*.py

📄 CodeRabbit inference engine (AGENTS.md)

Python code must pass Ruff linting via pre-commit

Files:

  • scripts/labctl.py
🧬 Code graph analysis (1)
docs/PRPs/containers/gitea.md (1)
docs/web/update-docs.py (1)
  • process_docker_compose_file (296-338)
🪛 dotenv-linter (3.3.0)
config-example/docker/myhost/.env

[warning] 12-12: [UnorderedKey] The STORAGE_OBSIDIAN key should go before the STORAGE_WEBDAV key

(UnorderedKey)


[warning] 101-101: [QuoteCharacter] The value has quote characters (', ")

(QuoteCharacter)


[warning] 103-103: [QuoteCharacter] The value has quote characters (', ")

(QuoteCharacter)


[warning] 103-103: [UnorderedKey] The GITEA_INTERNAL_TOKEN key should go before the GITEA_SECRET_KEY key

(UnorderedKey)


[warning] 107-107: [QuoteCharacter] The value has quote characters (', ")

(QuoteCharacter)

🪛 markdownlint-cli2 (0.18.1)
docs/PRPs/containers/mosquitto.md

4-4: Bare URL used

(MD034, no-bare-urls)


5-5: Bare URL used

(MD034, no-bare-urls)


6-6: Bare URL used

(MD034, no-bare-urls)


9-9: Bare URL used

(MD034, no-bare-urls)


80-80: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


90-90: Fenced code blocks should have a language specified

(MD040, fenced-code-language)

docs/PRPs/containers/esphome-device-builder.md

4-4: Bare URL used

(MD034, no-bare-urls)


5-5: Bare URL used

(MD034, no-bare-urls)


6-6: Bare URL used

(MD034, no-bare-urls)

docs/PRPs/containers/mssql-server.md

4-4: Bare URL used

(MD034, no-bare-urls)


6-6: Bare URL used

(MD034, no-bare-urls)

docs/PRPs/containers/gitea.md

4-4: Bare URL used

(MD034, no-bare-urls)


5-5: Bare URL used

(MD034, no-bare-urls)


6-6: Bare URL used

(MD034, no-bare-urls)


9-9: Bare URL used

(MD034, no-bare-urls)


80-80: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


90-90: Fenced code blocks should have a language specified

(MD040, fenced-code-language)

⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
  • GitHub Check: check
  • GitHub Check: build
🔇 Additional comments (1)
scripts/labctl.py (1)

32-32: Type annotation fix has been applied.

The type annotation for the since parameter has been corrected to str | None = None, addressing the issue raised in previous reviews.

Comment thread docker/guidelines.md Outdated
Comment thread docker/tools/Taskfile.obsidian.yaml
Comment thread docs/PRPs/containers/esphome-device-builder.md
@bubacoder
bubacoder force-pushed the feature/new-services branch from cbad2db to 6579fce Compare October 13, 2025 19:48
@bubacoder
bubacoder merged commit 82f476a into main Oct 13, 2025
4 checks passed
@bubacoder
bubacoder deleted the feature/new-services branch October 13, 2025 20:01
@coderabbitai coderabbitai Bot mentioned this pull request Nov 10, 2025
@coderabbitai coderabbitai Bot mentioned this pull request Jun 28, 2026
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