We heartily welcome any and all contributions that help make CARLOS a better EMR for the healthcare community. Whether you're fixing a typo, reporting a bug, improving documentation, or building a new feature, your effort matters and we appreciate you taking the time.
Remember: there are real people on the other side of the screen. Keep discussions positive, productive, and respectful.
- Ground Rules
- Ways to Contribute
- Development Environment Setup
- Contributing Code
- Code Standards
- Project Heritage
- Questions?
- License
All participants in the CARLOS community are expected to follow our Code of Conduct. In short: be respectful, be constructive, and remember that we're all working toward better healthcare software.
By contributing to CARLOS, you agree to the Developer Certificate of Origin (DCO). This is a lightweight agreement that certifies you have the right to submit your contribution under the project's open source license.
You sign off by adding a Signed-off-by line to your commit messages. Git can do this
automatically with the -s flag:
git commit -s -m "fix: your commit message"This adds a line like:
Signed-off-by: Your Name <your.email@example.com>
The DCO certifies that:
- You wrote the contribution, or have the right to submit it
- You understand it will be distributed under the project's open source license
- Your contribution is provided under the project's license terms
If you are contributing on behalf of your employer, the sign-off certifies that you have authorization to submit the work.
If the DCO check fails on your PR because commits are missing Signed-off-by lines, the
preferred fix is to amend or rebase your commits:
# Fix the most recent commit:
git commit --amend -s --no-edit
git push --force-with-lease
# Fix multiple commits (replace N with the number of commits):
git rebase --signoff HEAD~N
git push --force-with-leaseIf you cannot amend your commits (e.g., force-push is not possible), an authorized user can retroactively confirm DCO sign-off by posting a PR comment with the exact phrase:
Confirming DCO sign off for all commits
This will re-trigger the DCO check and allow it to pass. Only users with an established repository relationship (OWNER, MEMBER, COLLABORATOR, or CONTRIBUTOR) can use this alternate confirmation. First-time contributors must use the commit sign-off method.
Not all contributions require writing code. Here are some ways to get involved at any experience level:
5-10 minutes:
- Report a bug or request a feature via GitHub Issues
- Star the CARLOS repository to help others discover it
- Improve an error message or fix a typo
A few hours:
- Improve documentation or write a how-to guide
- Triage and reproduce reported bugs
- Review a pull request
Ongoing:
- Tackle a good first issue
- Implement a new feature or fix a complex bug
- Help with testing across different environments
Good bug reports help us fix issues faster. When filing an issue, please include:
- A clear, descriptive title
- Steps to reproduce the problem
- Expected vs. actual behavior
- Your environment (browser, OS, CARLOS version/branch)
- Screenshots or logs if applicable
Never include real patient data in bug reports. Use synthetic/test data only.
Use our bug report template to get started.
Our documentation lives in the docs/ directory and is written in Markdown. Improvements
to documentation are always welcome, whether it's fixing a typo, clarifying an explanation,
or adding a new guide.
For small changes, you can edit files directly on GitHub without cloning the repository.
- Docker Desktop installed and running
- VS Code with the Dev Containers extension
- Git
- Ports 8080 and 3306 must be available. The devcontainer uses these for the web application and database respectively. If another service (Tomcat, MySQL, etc.) is already using these ports, you'll need to stop it first or customize the port mappings in the Docker Compose configuration. If you run into conflicts, please let us know what you're seeing — PRs to improve our setup flexibility are welcome.
Docker accessing the Windows filesystem is significantly slow. We strongly recommend cloning the repository inside WSL (Windows Subsystem for Linux) and launching VS Code from within the WSL terminal. Both steps are important — the clone must live on the WSL filesystem, and VS Code must be started from inside WSL so the devcontainer runs against that filesystem.
It may work without WSL, but we do not test or QA that workflow on Windows and you should expect poor build and runtime performance.
# From a Windows terminal (PowerShell or CMD), install WSL with Ubuntu if needed
wsl --install -d Ubuntu
# Enter your WSL environment
wsl
# Clone inside WSL (not on /mnt/c/)
cd $HOME
mkdir -p dev && cd dev
# External contributors: fork on GitHub first, then clone your fork
git clone https://github.com/YOUR-USERNAME/carlos.git
# Internal contributors: clone the repo directly
git clone https://github.com/carlos-emr/carlos.git
cd carlos
# Launch VS Code from inside WSL
code .VS Code will detect the WSL environment automatically. When it prompts "Reopen in Container", the devcontainer will run with native Linux filesystem performance.
Straightforward. Make sure Docker Desktop is running and your user has Docker permissions
(typically membership in the docker group). Clone, open in VS Code, and reopen in
container.
# External contributors: fork on GitHub first, then clone your fork
git clone https://github.com/YOUR-USERNAME/carlos.git
# Internal contributors: clone the repo directly
git clone https://github.com/carlos-emr/carlos.git
cd carlos
code .Works similarly to Linux. There can be some performance impact due to Docker's filesystem layer on macOS, though it is less severe than on Windows. We may explore mounting the clone inside the container in the future to improve this — PRs welcome.
# External contributors: fork on GitHub first, then clone your fork
git clone https://github.com/YOUR-USERNAME/carlos.git
# Internal contributors: clone the repo directly
git clone https://github.com/carlos-emr/carlos.git
cd carlos
code .CARLOS uses a Docker-based devcontainer that provides a complete, isolated development environment with all dependencies pre-configured.
When VS Code prompts "Reopen in Container", click it. If you don't see the prompt, click the green remote connection icon in the bottom-left corner and select "Reopen in Container".
The first build takes several minutes as it initializes the database and downloads dependencies. Subsequent builds are much faster.
For detailed setup instructions, see .devcontainer/README.md.
Once inside the devcontainer:
make install # Build and deploy (without tests)On a fresh clone, make install is all you need. When rebuilding after making changes,
run make clean first to remove previous build artifacts:
make clean # Clean previous build artifacts
make install # Rebuild and deployAccess the application at http://localhost:8080. See the devcontainer README for login
credentials.
A note on make: Yes, wrapping Maven in a shell script is a bit of an anti-pattern
for Java/Maven purists. CARLOS has some build peculiarities — dual dependency lock files
for legacy and modern builds, WAR deployment with symlinks, Tomcat lifecycle management —
that make the raw mvn invocation non-trivial. The make script handles all of this so
developers can focus on developing, and it significantly smooths onboarding for new
contributors. If you come from a Maven-native background and have ideas for improving the
build workflow, those discussions are very welcome.
make install --run-tests # All tests (modern + legacy)
make install --run-unit-tests # Fast unit tests only (< 4 seconds)
make install --run-integration-tests # Integration tests (requires database)CARLOS uses develop as the default branch and the focus for all active development.
Pull requests and merges target develop. Releases are promoted from staging branches
to main. Do not work directly on develop — always create a feature branch for
your changes.
Internal contributors have push access to the CARLOS repository and can create
feature/, fix/, and other branches directly on the repo. If you've been granted
repository access, you can clone the CARLOS repo directly and push branches to it.
External contributors — and many valued contributors work this way — need to first fork the CARLOS repository to your own GitHub account (consider giving us a star while you're there!), then clone your fork to your local machine. You'll make changes and push branches to your fork, then open a pull request back to the CARLOS repository when your work is ready for review.
Both workflows end the same way: all changes go through a pull request targeting the
develop branch, reviewed and approved before merging. No one pushes directly to
protected branches.
- Fork the CARLOS repository on GitHub and clone your fork locally
- Add the upstream remote so you can keep your fork up to date:
git remote add upstream https://github.com/carlos-emr/carlos.git
- Sync your fork before starting new work:
git checkout develop git pull upstream develop git push origin develop
- Create a feature branch from
develop(never work directly ondevelop):git checkout -b your-feature-name
- Make your changes following the code standards below
- Test your changes - include tests for new functionality
- Commit with DCO sign-off (required — PRs without signed commits will not be accepted):
git commit -s -m "fix: description of your change" - Push to your fork:
git push origin your-feature-name
- Open a pull request on GitHub from your fork's branch to
carlos-emr/carlos:develop
- Clone the CARLOS repository directly
- Create a feature branch from
develop(never work directly ondevelop):git checkout develop git pull origin develop git checkout -b feature/your-feature-name
- Make and test your changes following the code standards below
- Commit with DCO sign-off (required — PRs without signed commits will not be accepted):
git commit -s -m "fix: description of your change" - Push your branch and open a pull request targeting
develop
All changes — from internal and external contributors alike — must go through a pull
request. Direct pushes to develop, main, and other protected branches are not allowed.
- Target
develop, nevermain - Reference related issues (e.g.,
fixes #123) - Include a clear description of what changed and why
- Add tests for new functionality
- Keep PRs focused - one logical change per PR
Your PR will be reviewed by a maintainer. We may ask for changes or suggest improvements. This is a normal part of the process and not a reflection on the quality of your work — we're all learning and improving together.
For bug fixes, feel free to open a PR directly. For new features, please open an issue first so we can discuss the approach and make sure it fits the project roadmap.
We use Conventional Commits:
feat: add patient allergy search filter
fix: correct date formatting in lab results
refactor: extract common validation logic in DemographicManager
chore: update Spring dependency to 5.3.39
docs: add deployment guide for BC clinics
test: add TicklerDao integration tests
CARLOS is a healthcare EMR built with Java 21, Spring 5.3, Struts 6.8, Hibernate 5.x, and MariaDB/MySQL. It handles sensitive patient data — security and code quality are not optional.
We strongly recommend developing inside the devcontainer, which provides the correct Java version, all dependencies, and a pre-configured database. Building outside the devcontainer is possible but unsupported — PRs to improve that experience are welcome.
Note for AI-assisted development: The .claude/ directory contains Claude Code
configuration with pre-approved permissions. These defaults assume an isolated devcontainer
environment with no real patient data. If you are using Claude Code outside a devcontainer,
review .claude/settings.json and restrict permissions as appropriate.
Every code change must follow these security practices:
- Output encoding: Use
Encode.forHtml(),Encode.forJavaScript(), and other context-appropriate OWASP Encoder methods for all user-provided data - Parameterized queries only: Never use string concatenation for SQL. Always use parameterized queries or Hibernate criteria
- Authorization checks: All actions must include
SecurityInfoManager.hasPrivilege()checks - File path validation: Use
PathValidationUtilsfor all file operations involving user input - No PHI in logs: Patient Health Information must never appear in log output or error messages
- Struts2 Actions: New actions follow the
*2Action.javanaming convention (e.g.,AddTickler2Action.java). See existing actions for examples. - Spring Integration: Use
SpringUtils.getBean()for dependency injection - Package namespace: All new code uses
io.github.carlos_emr.carlos.* - Copyright headers: New files use the CARLOS project header
(see
docs/copyright-header-carlos.md). Never remove existing copyright notices from modified files - this is required by the GPL.
- Modern tests use JUnit 5 in
src/test-modern/ - Follow BDD naming:
shouldReturnTickler_whenValidIdProvided() - Extend
OpenOTestBasefor integration tests,OpenOUnitTestBasefor unit tests - See
docs/test/test-writing-guide.mdfor detailed patterns
CARLOS has evolved through multiple open-source projects over 20+ years. You may encounter references to "OSCAR", "OpenO", or "OpenOSP" in code comments, git history, and legacy documentation. These reflect the project's heritage, not current affiliations. See NOTICE.md for full attribution details.
If you're stuck, confused, or just want to say hello, open a GitHub Issue. We'd rather you ask than struggle in silence. We plan to enable GitHub Discussions in the future for broader conversation.
CARLOS as a project is licensed under GPL-2.0. Refer to individual file headers for further license and copyright information. See COPYING.md for the full license text and NOTICE.md for project attribution.