Skip to content

Add Habitify chat tools plugin#4776

Closed
aaravgarg wants to merge 6 commits intomainfrom
feature/habitify-plugin
Closed

Add Habitify chat tools plugin#4776
aaravgarg wants to merge 6 commits intomainfrom
feature/habitify-plugin

Conversation

@aaravgarg
Copy link
Copy Markdown
Collaborator

Summary

  • Adds a new Habitify plugin at plugins/habitify/ for managing habits via Omi chat
  • 7 chat tools: list habits, get status, complete habit, get logs, daily summary, add note, log mood
  • API key auth (simple form entry, validated against Habitify API)
  • OpenAI-powered fuzzy habit name matching with substring fallback
  • Redis + JSON file fallback storage (same pattern as Mixpanel plugin)

Test plan

  • Verify manifest at /.well-known/omi-tools.json returns all 7 tools
  • Test auth flow with a Habitify API key
  • Test each tool endpoint with real Habitify data
  • Verify error handling for invalid API keys and missing habits
  • Deploy to Railway and test end-to-end with Omi app

🤖 Generated with Claude Code

aaravgarg and others added 6 commits February 12, 2026 23:11
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
FastAPI app with 7 chat tools: list habits, get status, complete habit,
get logs, daily summary, add note, log mood. Uses OpenAI for fuzzy
habit name matching with simple substring fallback.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Copy link
Copy Markdown
Contributor

@gemini-code-assist gemini-code-assist Bot left a comment

Choose a reason for hiding this comment

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

Code Review

This pull request introduces a new Habitify chat tools plugin for Omi chat, enabling habit management, mood logging, and progress tracking. It contains critical security vulnerabilities, specifically Reflected Cross-Site Scripting (XSS) due to unescaped user input and Broken Access Control (IDOR) due to a lack of uid parameter authentication. Additionally, there are concerns regarding API key storage, inefficient local storage implementation, and broad exception handling that need to be addressed.

Comment thread plugins/habitify/main.py
Comment on lines +94 to +95
data = json.dumps({"api_key": api_key})
store_set(_creds_key(uid), data)
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.

critical

Storing the api_key directly without encryption is a critical security vulnerability. API keys are sensitive credentials and should always be encrypted at rest, especially when persisted to a file or database. An attacker gaining access to the storage could compromise user accounts. Consider using a robust encryption mechanism (e.g., AES) with a securely managed key.

Comment thread plugins/habitify/main.py
Comment on lines +79 to +81
_load_local()
_local_store.pop(key, None)
_save_local()
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.

high

Calling _load_local() and _save_local() on every store_delete operation when Redis is not configured is inefficient. This results in a file read and write for every deletion. This can lead to performance issues and potential data corruption if multiple processes try to modify the file concurrently.

Comment thread plugins/habitify/main.py
Comment on lines +203 to +204
except Exception:
pass
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.

high

Catching a generic Exception for OpenAI API calls is too broad. This can hide specific issues with the OpenAI API (e.g., openai.APIError, openai.RateLimitError) or other unexpected errors. It's better to catch specific exceptions to handle them appropriately or log them for debugging, rather than silently suppressing all errors.

Comment thread plugins/habitify/main.py


@app.get("/", response_class=HTMLResponse)
async def root(uid: Optional[str] = Query(None)):
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.

security-high high

The application relies solely on a user-supplied uid to identify users and manage their Habitify API keys across all endpoints. There is no authentication or authorization mechanism (such as session tokens, JWTs, or request signing) to verify the identity of the requester. This constitutes a Broken Access Control / Insecure Direct Object Reference (IDOR) vulnerability, allowing any attacker who knows a user's uid to access, modify, or delete their credentials and perform actions on their behalf.

Recommendation: Implement a secure authentication flow. If this plugin is intended for use by the Omi backend, implement request signature verification or use a shared secret.

Comment thread plugins/habitify/main.py
@@ -0,0 +1,1108 @@
import os
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.

security-high high

Import the html module to enable escaping of user-supplied data in HTML responses.

Suggested change
import os
import os, html

Comment thread plugins/habitify/main.py
Comment on lines +903 to +904
except Exception as e:
return ChatToolResponse(error=f"Failed to complete habit: {str(e)}")
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.

high

Catching a generic Exception can hide unexpected errors and make debugging difficult. It's better to catch more specific exceptions (e.g., httpx.RequestError, httpx.TimeoutException) to handle known failure modes gracefully, while allowing unexpected issues to propagate.

Comment thread plugins/habitify/main.py
Comment on lines +937 to +938
except Exception as e:
return ChatToolResponse(error=f"Failed to fetch logs: {str(e)}")
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.

high

Catching a generic Exception can hide unexpected errors and make debugging difficult. It's better to catch more specific exceptions (e.g., httpx.RequestError, httpx.TimeoutException) to handle known failure modes gracefully, while allowing unexpected issues to propagate.

Comment thread plugins/habitify/main.py
Comment on lines +994 to +995
except Exception:
return habit, {}
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.

high

Catching a generic Exception within the _get_status coroutine can hide unexpected errors during concurrent API calls. This can make it difficult to diagnose issues with individual habit status fetches. Consider logging the exception or returning a more specific error indicator for better debugging.

Comment thread plugins/habitify/main.py
Comment on lines +1069 to +1070
return ChatToolResponse(error=f"Habitify API error: {e.response.status_code}")
except Exception as e:
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.

high

Catching a generic Exception can hide unexpected errors and make debugging difficult. It's better to catch more specific exceptions (e.g., httpx.RequestError, httpx.TimeoutException) to handle known failure modes gracefully, while allowing unexpected issues to propagate.

Comment thread plugins/habitify/main.py
Comment on lines +1106 to +1107
return ChatToolResponse(error=f"Habitify API error: {e.response.status_code}")
except Exception as e:
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.

high

Catching a generic Exception can hide unexpected errors and make debugging difficult. It's better to catch more specific exceptions (e.g., httpx.RequestError, httpx.TimeoutException) to handle known failure modes gracefully, while allowing unexpected issues to propagate.

@beastoin
Copy link
Copy Markdown
Collaborator

Closing this stale draft — no activity in 3+ days. Feel free to reopen when it's ready for review.

@beastoin beastoin closed this Feb 17, 2026
@github-actions
Copy link
Copy Markdown
Contributor

Hey @aaravgarg 👋

Thank you so much for taking the time to contribute to Omi! We truly appreciate you putting in the effort to submit this pull request.

After careful review, we've decided not to merge this particular PR. Please don't take this personally — we genuinely try to merge as many contributions as possible, but sometimes we have to make tough calls based on:

  • Project standards — Ensuring consistency across the codebase
  • User needs — Making sure changes align with what our users need
  • Code best practices — Maintaining code quality and maintainability
  • Project direction — Keeping aligned with our roadmap and vision

Your contribution is still valuable to us, and we'd love to see you contribute again in the future! If you'd like feedback on how to improve this PR or want to discuss alternative approaches, please don't hesitate to reach out.

Thank you for being part of the Omi community! 💜

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.

2 participants